• This notebook summarizes the results from temporal covariance analysis from CVTKPY.
  • The covariance window size used was 100k (but the window sizes did not affect the results)

1 Results from CVTKPY: genome-wide temporal covariances of allele frequencies

pops<-c("PWS","TB","SS")

covs<-data.frame()
for (p in 1: length(pops)){
    #covariance output file
    cov<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/3Pops_maf05_temp_cov_matrix_",pops[p],"_100k.csv"))
    cov<-cov[,-1]
        
    #reshape the matrix
    mat1<-cov[1:3,]
    mat2<-cov[4:6,]
        
    covdf<-data.frame()
    k=1
    for (i in 1:nrow(mat1)){
        for (j in 1:ncol(mat1)){
            covdf[k,1]<-mat2[i,j]
            covdf[k,2]<-mat1[i,j]
            k=k+1
        }
    }
    colnames(covdf)<-c("label","value")
    covdf$value<-as.numeric(covdf$value)
    covar<-covdf[grep("cov",covdf$label),]
        
    #remove the redundant values
    if (pops[p]!="SS") covar<-covar[!duplicated(covar[, 2]),] 
    if (pops[p]=="SS") covar<-covar[c(1,2,4),]
        
    #assign the starting time period and covering period values
    covar$year<-c(1,2,2)
    covar$series<-c("1991","1991","1996")
        
    #assign population name
    covar$location<-pops[p]
    
    #combine in to one matrix
    covs<-rbind(covs, covar)
}

covs$time<-rep(c("cov12","cov13","cov23"), 3)
colnames(covs)[2]<-"cov"

# 95% confidence intervals (calculated from the 'straps' returned from bootstrap_cov2() ci=1.96*sd(straps))
time<-c("cov12","cov13","cov23")

covs$ci<-NA
for (i in 1:length(pops)){  
     if (i!=3){
        df<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pops[i],"_CIs_100kwindow.csv"), header=F)
        covs$ci[covs$location==pops[i]&time=='cov12']<-df[1,2]
        covs$ci[covs$location==pops[i]&time=='cov13']<-df[1,3]
        covs$ci[covs$location==pops[i]&time=='cov23']<-df[2,3]
    }
    if (p==3) {
        df<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pops[i],"_CIs_100kwindow.csv"), header=F)
        covs$ci[covs$location==pops[i]&time=='cov23']<-df[1,2] 
    }
}

write.csv(covs,"../Output/COV/GW_covariance_CIs.csv")

xtexts<-c("\u03941991-1996\n ~ \u03941996-2006", "\n  ~ \u03942006-2017")

ggplot(data=covs, aes(x=year, y=cov, color=location, shape=series, group=interaction(location, series)))+
        geom_point(size=3, position=position_dodge(width = 0.1,preserve ="total"))+
        geom_line(data=covs, aes(x=year, y=cov,color=location, group=interaction(location, series)), position=position_dodge(width = 0.1,preserve ="total"))+
        ylab("Covariance")+xlab('')+theme_classic()+
        theme(legend.title = element_blank())+
        geom_hline(yintercept = 0,color="gray70", size=0.3)+
        geom_errorbar(aes(ymin=cov-ci, ymax=cov+ci), width=.2, size=.2, position=position_dodge(width = 0.1,preserve ="total"))+
        scale_shape_manual(values=c(16,17),labels=c("\u0394'91-'96~","\u0394'96-'06~"))+
        scale_x_continuous(breaks = c(1,2), labels=xtexts)+
        scale_color_manual(values=cols[c(2,3,1)])+ylim(-0.0023,0.002)
ggsave(paste0("../Output/COV/3Pops_Cov_overtime_CIestimated.png"),width = 4.7, height = 3, dpi=300)
    
covs$time<-factor(covs$time, levels=c("cov12","cov23","cov13"))
#xtexts<-c("\u03941991-1996\n ~ \u03941996-2006", "\u03941996-2006\n  ~ \u03942006-2017", "\u03941991-1996\n  ~ \u03942006-2017")
xtexts<-c("\u0394'91-'96\n ~ \u0394'96-'06", "\u0394'96-'06\n  ~ \u0394'06-'17", "\u0394'91-'96\n  ~ \u0394'06-'17")

ggplot(data=covs, aes(x=time, y=cov, color=location))+
        geom_point(size=3, position=position_dodge(width = 0.1,preserve ="total"))+
        #geom_line(data=covs, aes(x=year, y=cov,color=location, group=interaction(location, series)), position=position_dodge(width = 0.1,preserve ="total"))+
        ylab("Covariance")+xlab('')+theme_classic()+
        theme(legend.title = element_blank(), axis.text.x = element_text(size=9))+
        geom_hline(yintercept = 0,color="gray70", size=0.3)+
        geom_errorbar(aes(ymin=cov-ci, ymax=cov+ci), width=.2, size=.2, position=position_dodge(width = 0.1,preserve ="total"))+
        scale_x_discrete(labels=xtexts)+
    scale_color_manual(values=cols[c(2,3,1)])+
    geom_vline(xintercept = c(1.5,2.5), color="gray", size=0.2)+ylim(-0.0023,0.002)
ggsave(paste0("../Output/COV/3Pops_Cov_CI_3timepoints.png"),width = 4.57, height = 3, dpi=300)

2 Find regions with high covariances in each population

  • From Temporal Covariance analysis -output covariances for each time period

2.1 Plot the covariances across the genome

#Find the regions with a high temporal covariance 
pops<-c("PWS","TB","SS")
winsize<-"100k"
evens<-paste0("chr",seq(2,26, by=2))
cov.list<-list()
covs_all<-list()
k=1
for (p in 1: length(pops)){
    pop<-pops[p]
    iv<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/3pops_intervals_",winsize,"window.csv"), row.names = 1)
    if (p==3) {
        cov23<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov23_2017-2006_2006-1996_3Pops_",winsize,"window.csv"), header = F)
        covs<-cbind(iv, cov23)
        colnames(covs)[4]<-c("cov23")
        covs$index=1:nrow(covs)
        covs$color<-"col1"
        covs$color[covs$chrom %in% evens]<-"col2"

        covs[sapply(covs, is.infinite)] <- NA
        covs[sapply(covs, is.nan)] <- NA
        
        cov.list[[k]]<-covs
        names(cov.list)[k]<-paste0(pop,"_",winsize)    
        k=k+1
            
        y<-min(covs$cov23, na.rm=T)
        ymin<-ifelse (y<=-0.1,-0.1, y) 
        ymax<-max(covs$cov23, na.rm=T)
        ggplot(covs, aes(x=index, y=cov23, color=color))+
            geom_point(size=1, alpha=0.5)+
            theme_classic()+
            ylim(ymin,ymax)+
            scale_color_manual(values=c("gray70","steelblue"), guide="none")+
            ylab("Covariance")+xlab('Chromosome')+
            theme(axis.text.x = element_blank())+
            ggtitle(paste0(pop," ", winsize," window"))
        #ggsave(paste0("../Output/COV/3Pops.",pop,"_tempCovs_acrossGenome_",winsize[i], "Window.png"), width = 8, height = 2.7, dpi=300) 
        }
    else {
        cov12<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov12_1996-1991_2006-1996_3Pops_",winsize,"window.csv"), header = F)
        cov23<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov23_2017-2006_2006-1996_3Pops_",winsize,"window.csv"), header = F)
        cov13<-read.csv(paste0("~/Projects/Pacherring_Vincent/MD7000/",pop,"_cov13_2017-2006_1996-1991_3Pops_",winsize,"window.csv"), header = F)
        covs<-cbind(iv, cov12, cov23,cov13)
        colnames(covs)[4:6]<-c("cov12","cov23","cov13")
        covs$index=1:nrow(covs)
    
        covs$color<-"col1"
        covs$color[covs$chrom %in% evens]<-"col2"
    
        covs[sapply(covs, is.infinite)] <- NA
        covs[sapply(covs, is.nan)] <- NA
        
        cov.list[[k]]<-covs
        names(cov.list)[k]<-paste0(pop,"_",winsize)    
        k=k+1
        covsm<-melt(covs[,c("index","color","cov12","cov23","cov13")], id.vars = c("index", "color"))
        ymax<-max(covsm$value, na.rm=T)
        y<-min(covsm$value, na.rm=T)
        ymin<-ifelse (y<=-0.1,-0.1, y) 
        ggplot(covsm, aes(x=index, y=value, color=color))+
            facet_wrap(~variable, nrow=3)+
            geom_point(size=1, alpha=0.5)+
            theme_classic()+
            ylim(ymin,ymax)+
            scale_color_manual(values=c("gray70","steelblue"), guide="none")+
            ylab("Covariance")+xlab('Chromosome')+
            theme(axis.text.x = element_blank())+
            ggtitle(paste0(pop," ", winsize," window"))
        #ggsave(paste0("../Output/COV/3Pops.",pop,"_tempCovs_acrossGenome_",winsize, "Window.png"), width = 8, height = 8, dpi=300)    
    }
}

3 Find the covariance lower cut off values

cv<-c("cov12","cov13","cov23")
cvrange<-data.frame(pop=c(paste0(pops[1:2],"_", cv[1]),paste0(pops[1:2],"_", cv[2]),paste0(pops,"_", cv[3])))
k=1
for (i in 1:length(cv)){
    if (i==1|i==2){
        if (i==1) k=1
        if (i==2) k=3
        #PWS
        df1<-cov.list[[paste0("PWS_100k")]]
        df1<-df1[order(df1[,cv[i]], decreasing=T),]
        n<-ceiling(nrow(df1)*0.01) #top1% region
        df1$top1<-"N"
        df1$top1[1:n]<-"PWS"
        rg<-range(df1[df1$top1=="PWS",cv[i]], na.rm=T)
        cvrange[k,"100k"]<-paste0(rg[1],"-",rg[2])
          
        #tb
        df2<-cov.list[["TB_100k"]]
        df2<-df2[order(df2[,cv[i]], decreasing=T),]
        df2$top1<-"N"
        df2$top1[1:n]<-"TB"
        rg2<-range(df2[df2$top1=="TB", cv[i]], na.rm=T)
        cvrange[(k+1),"100k"]<-paste0(rg2[1],"-",rg2[2])
    }
   
    if (i==3){
        k=5
        #pws
        df1<-cov.list[["PWS_100k"]]
        df1<-df1[,c("chrom","start","end","cov23")]
        df1<-df1[order(df1$cov23, decreasing=T),]
        n<-ceiling(nrow(df1)*0.01) #top1% region
        df1$top1<-"N"
        df1$top1[1:n]<-"PWS"
        
        rg<-range(df1[df1$top1=="PWS",cv[i]], na.rm=T)
        cvrange[k,"100k"]<-paste0(rg[1],"-",rg[2])
           
        #tb
        df2<-cov.list[["TB_100k"]]
        df2<-df2[,c("chrom","start","end","cov23")]
        df2<-df2[order(df2$cov23, decreasing=T),]
        df2$top1<-"N"
        df2$top1[1:n]<-"TB"
        rg2<-range(df2[df2$top1=="TB", cv[i]], na.rm=T)
        cvrange[(k+1),"100k"]<-paste0(rg2[1],"-",rg2[2])
    
        #ss
        df3<-cov.list[["SS_100k"]]
        df3<-df3[,c("chrom","start","end","cov23")]
        df3<-df3[order(df3$cov23, decreasing=T),]
        df3$top1<-"N"
        df3$top1[1:n]<-"SS"
        rg3<-range(df3[df3$top1=="SS", cv[i]], na.rm=T)
        cvrange[(k+2),"100k"]<-paste0(rg3[1],"-",rg3[2])
        }
    }
}

cvs<-melt(cvrange, id.vars = "pop")
cvs<-cvs %>%
  separate(value, c("low", "high"), "-")
cvs$low<-as.numeric(cvs$low)
cvs$high<-as.numeric(cvs$high)
cvs<-cvs%>%
  separate(pop, c("pop", "cov"), "_")

ggplot(cvs, aes(x=cov, y=high, fill=pop))+
    geom_crossbar(aes(ymin=low, ymax=high), width=0.5, position=position_dodge(width = 1))+
    ylab("Range of covariances")+
    theme_light()+xlab("")+
    geom_vline(xintercept=c(1.5,2.5), color="gray")+
    theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.title=element_blank())+
    ggtitle("Top1% Cov Range")
ggsave("../Output/COV/COVscan_3pop/TempCov_Range_comparison_100k.png", width = 5, height = 3, dpi=300)

ggplot(cvs, aes(x=cov, y=low, color=pop))+
    geom_point()+
    ylab("Lower limit of top 1% covariance")+
    theme_light()+xlab("")+
    geom_vline(xintercept=c(1.5,2.5), color="gray")+
    theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.title=element_blank())
ggsave("../Output/COV/COVscan_3pop/TempCov_Range_lowLimit_comparison_100k.png", width = 5, height = 3, dpi=300)

3.1 Use the lowest covariance values for each period to definte outlier regions

lows<-aggregate(cvs$low, by=list(cvs$cov), min)
names(lows)<-c("cov","low")
#low cutoff for each time period (100k-window)
#     cov        low
#1 cov12 0.02874841
#2 cov13 0.03102712
#3 cov23 0.03246524


# Outliers based on the new low cut-off values 100k window. 
cov12<-data.frame()
cov23<-data.frame()
cov13<-data.frame()

for (i in 1:length(cov.list)){
 #PWS and TB
  if (i==1|i==2){
    covs<-cov.list[[i]]
    pop<-gsub("_.+",'', names(cov.list)[i])
  
    #outlier cutoff value
    x<-lows$low[lows$cov=="cov12"]
    covs12_top<-subset(covs, cov12>=x)
    covs12_top<-covs12_top[order(covs12_top$chrom, covs12_top$start),]
    covs12_top$pop<-pop
    cov12<-rbind(cov12, covs12_top)
    
    covs<-covs[order(covs$cov13, decreasing=T),]
    x<-lows$low[lows$cov=="cov13"]
    covs13_top<-subset(covs, cov13>=x)
    covs13_top<-covs13_top[order(covs13_top$chrom, covs13_top$start),]
    covs13_top$pop<-pop
    cov13<-rbind(cov13, covs13_top)
    
    covs<-covs[order(covs$cov23, decreasing=T),]
    x<-lows$low[lows$cov=="cov23"]
    covs23_top<-subset(covs[,c("chrom","start","end","cov23","index","color")], cov23>=x)
    covs23_top<-covs23_top[order(covs23_top$chrom, covs23_top$start),]
    covs23_top$pop<-pop
    cov23<-rbind(cov23, covs23_top)
 }
 if (grepl("SS",names(cov.list)[i])){
    covs<-cov.list[[i]]
    
    pop<-gsub("_.+",'', names(cov.list)[i])
    win<-gsub(paste0(pop,"_"), '', names(cov.list)[i])
    
    covs<-covs[order(covs$cov23, decreasing=T),]
    x<-lows$low[lows$cov=="cov23"]
    covs23_top<-subset(covs, cov23>=x)
    covs23_top<-covs23_top[order(covs23_top$chrom, covs23_top$start),]
    covs23_top$pop<-pop
    cov23<-rbind(cov23, covs23_top)
    }
}

write.csv(cov12, "../Output/COV/COVscan_3pop/cutoff/3pops_top1percent_outlier_cutoff.cov12.csv",row.names = F)
write.csv(cov23, "../Output/COV/COVscan_3pop/cutoff/3pops_top1percent_outlier_cutoff.cov23.csv",row.names = F)
write.csv(cov13, "../Output/COV/COVscan_3pop/cutoff/3pops_top1percent_outlier_cutoff.cov13.csv",row.names = F)

3.1.1 Strickter covariance cutoff

#
cov12<-data.frame()
cov23<-data.frame()
cov13<-data.frame()
names(cov.list)
for (i in 1:length(cov.list)){
 #PWS and TB
  if (i==1|i==2){
    covs<-cov.list[[i]]
    pop<-gsub("_.+",'', names(cov.list)[i])
    
    plot(covs$cov12)
  
    #outlier cutoff value
    x<-lows$low[lows$cov=="cov12"]
    covs12_top<-subset(covs, cov12>=x)
    # cov cutoff at 0.035
    c12<-covs12_top[covs12_top$cov12 >0.035,] 
    
    #create a bed file for the reion
    df<-c12[,c("chrom","start","end")]
    #add 100k
    df$start<-df$start-100000
    df$end<-df$end+100000
    dfp<-df[df$pop=="PWS",1:3]
    colnames(dfp)<-c('track type=bedGraph', '1','1')
    write.table(dfp, paste0("../Output/COV/COVscan_3pop/cutoff/PWS_outliers_",cv[i],"_new.bed"),quote = F, row.names = F, col.names = T,sep = "\t")
  
    
    covs12_top<-covs12_top[order(covs12_top$chrom, covs12_top$start),]
    covs12_top$pop<-pop
    cov12<-rbind(cov12, covs12_top)
    
    covs<-covs[order(covs$cov13, decreasing=T),]
    x<-lows$low[lows$cov=="cov13"]
    covs13_top<-subset(covs, cov13>=x)
    covs13_top<-covs13_top[order(covs13_top$chrom, covs13_top$start),]
    covs13_top$pop<-pop
    cov13<-rbind(cov13, covs13_top)
    
    covs<-covs[order(covs$cov23, decreasing=T),]
    x<-lows$low[lows$cov=="cov23"]
    covs23_top<-subset(covs[,c("chrom","start","end","cov23","index","color")], cov23>=x)
    covs23_top<-covs23_top[order(covs23_top$chrom, covs23_top$start),]
    covs23_top$pop<-pop
    cov23<-rbind(cov23, covs23_top)
 }
 if (grepl("SS",names(cov.list)[i])){
    covs<-cov.list[[i]]
    
    pop<-gsub("_.+",'', names(cov.list)[i])
    win<-gsub(paste0(pop,"_"), '', names(cov.list)[i])
    
    covs<-covs[order(covs$cov23, decreasing=T),]
    x<-lows$low[lows$cov=="cov23"]
    covs23_top<-subset(covs, cov23>=x)
    covs23_top<-covs23_top[order(covs23_top$chrom, covs23_top$start),]
    covs23_top$pop<-pop
    cov23<-rbind(cov23, covs23_top)
    }
}

3.2 Create plots with different colors for outliers

#for COV12 and COV13 for TB and PWS (100K)
cv<-c("cov12","cov13","cov23")

for (i in 1:length(cv)){
    if (i==1|i==2){
        #cutoff value
        x<-lows$low[lows$cov==cv[i]]
        #PWS
        df1<-cov.list[["PWS_100k"]]
        df1<-df1[order(df1[,cv[i]], decreasing=T),]
        df1$top1<-"N"
        df1$top1[df1[,cv[i]]>=x]<-"PWS"
        
        #tb
        df2<-cov.list[["TB_100k"]]
        df2<-df2[order(df2[,cv[i]], decreasing=T),]
        df2$top1<-"N"
        df2$top1[df2[,cv[i]]>=x]<-"TB"
        
        #Combine PWS and TB tables
        co<-rbind(df1, df2)
        co$chrom<-factor(co$chrom, levels=paste0("chr", 1:26))
        co$top1<-factor(co$top1, levels=c("PWS","TB","N"))
        colnames(co)[which(colnames(co)==cv[i])]<-"cov"
    
        ymax<-max(co$cov, na.rm=T)
        #Plot each genome separately
        ggplot(co, aes(x=start/1000000, y=cov, color=top1))+
            geom_point(size=0.5)+
            facet_wrap(~chrom, ncol=4)+
            theme_classic()+ylim(-0.1,ymax)+
            scale_color_manual(values=c(paste0(cols[2],"B3"),paste0(cols[1],"B3") ,"#C0C0C080"), labels=c("PWS", "TB", ""))+
            ylab("Covariance")+xlab('Postion (Mb)')+
            ggtitle(cv[i])+
            scale_x_continuous(labels = comma)+
            guides(color = guide_legend(override.aes = list(color=c(cols[2],cols[1],"white"),size=2), title=element_text("Top 1%")))
   
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/3Pops.",cv[i],"_perChrom_100k_Window_Outliers.png"), width = 10, height = 8, dpi=300)
        
        #Whole genome in 1 plot 
        #assign colors
        co$top1<-apply(co, 1, function(x) {ifelse (x['top1']=="N", x['color'], x['top1'])} )
        co$top1<-factor(co$top1, levels=c("PWS","TB","col1","col2"))
        
        #count the number of sites per chromosomes
        poss<-data.frame(chr=paste0("chr",1:26))
        k=1
        for (j in 1:26){
            df<-df1[df1$chr==paste0("chr",j),]
            poss$start[j]<-k
            poss$end[j]<-k+nrow(df)-1
            k=k+nrow(df)
        }
        poss$x<-poss$start+(poss$end-poss$start)/2
        ymax<-max(co$cov, na.rm=T)
        ggplot(co, aes(x=index, y=cov, color=top1))+
            geom_point(size=0.5)+
            theme_classic()+ylim(-0.1,ymax)+
            scale_color_manual(values=c(paste0(cols[2],"B3"),paste0(cols[1],"B3"),"#A8BBCD66","#D6D6D666"), labels=c("PWS", "TB", "",""))+
            ylab("Covariance")+
            ggtitle(paste0(" 100k window ",cv[i]))+
            guides(color = guide_legend(override.aes = list(color=c(cols[2], cols[1],"white","white"), size=2), title=element_text("Outlier Region", size=10)))+
            scale_x_continuous(name="Chromosome", breaks=poss$x, labels=1:26)
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/3Pops.",cv[i],"_100k_Window_Outliers.png"), width = 10, height = 3.5, dpi=300)
    }
   
    if (i==3){
       #cutoff value
        x<-lows$low[lows$cov==cv[i]]
        #PWS
        df1<-cov.list[["PWS_100k"]]
        df1<-df1[,c("chrom","start","end","cov23","index","color")]
        df1<-df1[order(df1$cov23, decreasing=T),]
        df1$top1<-"N"
        df1$top1[df1[,cv[i]]>=x]<-"PWS"
        
        #tb
        df2<-cov.list[["TB_100k"]]
        df2<-df2[,c("chrom","start","end","cov23","index","color")]
        df2<-df2[order(df2$cov23, decreasing=T),]
        df2$top1<-"N"
        df2$top1[df2[,cv[i]]>=x]<-"TB"
    
        #ss
        df3<-cov.list[["SS_100k"]]
        df3<-df3[,c("chrom","start","end","cov23","index","color")]
        df3<-df3[order(df3$cov23, decreasing=T),]
        df3$top1<-"N"
        df3$top1[df3[,cv[i]]>=x]<-"SS"

        co<-rbind(df1,df2,df3)

        co$chrom<-factor(co$chrom, levels=paste0("chr", 1:26))
        co$top1<-factor(co$top1, levels=c("PWS","TB","SS","N"))
        ymax<-max(co$cov23, na.rm=T)
        ggplot(co, aes(x=start/1000000, y=cov23, color=top1))+
            geom_point(size=0.6)+
            facet_wrap(~chrom, ncol=4)+
            theme_classic()+ylim(-0.1,ymax)+
            ylab("Covariance")+xlab('Postion (Mb)')+
            ggtitle(cv[i])+
            scale_x_continuous(labels = comma)+
            #scale_color_discrete(breaks=c("PWS","SS","TB"))+
            scale_color_manual(values=c(paste0(cols[c(2,1,3)],"B3"),"#C0C0C088"), labels=c("PWS","TB","SS", ""))+
            guides(color = guide_legend(override.aes = list(color=c(cols[c(2,1,3)],"white"), size=2),title=element_text("Top 1% outliers"))) 
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/3Pops.cov23_perChrom_100k_Window_Outliers.png"), width = 10, height = 9, dpi=300)
        
        #assign colors
        co$top1<-apply(co, 1, function(x) {ifelse (x['top1']=="N", x['color'], x['top1'])} )
        co$top1<-factor(co$top1, levels=c("PWS","TB","SS","col1","col2"))
        #count the number of sites per chromosomes
        poss<-data.frame(chr=paste0("chr",1:26))
        k=1
        for (j in 1:26){
            df<-df1[df1$chr==paste0("chr",j),]
            poss$start[j]<-k
            poss$end[j]<-k+nrow(df)-1
            k=k+nrow(df)
        }
        poss$x<-poss$start+(poss$end-poss$start)/2
        ymax<-max(co$cov, na.rm=T)
        ggplot(co, aes(x=index, y=cov23, color=top1))+
            geom_point(size=0.5)+
            theme_classic()+ylim(-0.1,ymax)+
            scale_color_manual(values=c(paste0(cols[c(2,1,3)],"B3"),"#A8BBCD66","#D6D6D666"), labels=c("PWS", "TB","SS", "",""))+
                ylab("Covariance")+
                ggtitle(paste0(" 100k window ",cv[i]))+
                guides(color = guide_legend(override.aes = list(color=c(cols[c(2,1,3)],"white","white"), size=2), title=element_text("Outlier (1%)")))+
            scale_x_continuous(name="Chromosome", breaks=poss$x, labels=1:26)+
            theme(legend.title = element_text(size=10))
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/3Pops.",cv[i],"_100k_Window_Outliers.png"), width = 10, height = 3.5, dpi=300)
        }
        
}

3.2.1 Whole genome plots all time priods for PWS and TB

## Plot 3 time periods together for PWS and TB
Cov<-data.frame()
for (i in 1:length(cv)){
    #cutoff value
    x<-lows$low[lows$cov==cv[i]]
    #PWS
    df1<-cov.list[["PWS_100k"]]
    df1<-df1[order(df1[,cv[i]], decreasing=T),]
    df1$top1<-"N"
    df1$top1[df1[,cv[i]]>=x]<-"PWS"
    
    #tb
    df2<-cov.list[["TB_100k"]]
    df2<-df2[order(df2[,cv[i]], decreasing=T),]
    df2$top1<-"N"
    df2$top1[df2[,cv[i]]>=x]<-"TB"
    
    #Combine PWS and TB tables
    co<-rbind(df1, df2)
    co$chrom<-factor(co$chrom, levels=paste0("chr", 1:26))
    colnames(co)[which(colnames(co)==cv[i])]<-"cov"
    #assgin colors
    co$top1<-apply(co, 1, function(x) {ifelse (x['top1']=="N", x['color'], x['top1'])} )
    co$top1<-factor(co$top1, levels=c("PWS","TB","col1","col2"))
    co$time<-cv[i]
    
    Cov<-rbind(Cov, co[,c("index", "cov","top1","time")])
}

#count the number of sites per chromosomes
df1<-cov.list[["PWS_100k"]]
poss<-data.frame(chr=paste0("chr",1:26))
k=1
for (j in 1:26){
        df<-df1[df1$chr==paste0("chr",j),]
        poss$start[j]<-k
        poss$end[j]<-k+nrow(df)-1
        k=k+nrow(df)
}
poss$x<-poss$start+(poss$end-poss$start)/2
ymax<-max(co$cov, na.rm=T)
ggplot(Cov, aes(x=index, y=cov, color=top1))+
    facet_wrap(~time, ncol=1)+
    geom_point(size=0.5)+
    theme_classic()+ylim(-0.1,ymax)+
    scale_color_manual(values=c(paste0(cols[c(2,1)],"B3"),"#A8BBCD66","#D6D6D666"), labels=c("PWS", "TB", "",""))+
    ylab("Covariance")+
    guides(color = guide_legend(override.aes = list(color=c(cols[c(2,1)],"white","white"), size=2), title=element_text("Outlier", size=10)))+
    scale_x_continuous(name="Chromosome", breaks=poss$x, labels=1:26)

ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/PWS_TB_100k_Window_Outliers.png"), width = 11, height = 5, dpi=300)
        }}

3.3 Overlapping outlier regions between different populations

#100k
cv<-c("cov12","cov13","cov23")
pairs<-t(combn(pops, 2))
pairs<-data.frame(pairs)
colnames(pairs)<-paste0("pop",1:2)
Ov_direct<-data.frame(cov=c(cv[1:2],"cov23-PT","cov23-PS","cov23-ST" ,"cov23-3"))
Ov_300<-data.frame(cov=c(cv[1:2],"cov23-PT","cov23-PS","cov23-ST" ,"cov23-3"))
for (i in 1:length(cv)){
    df<-read.csv(paste0("../Output/COV/COVscan_3pop/cutoff/3pops_top1percent_outlier_cutoff.", cv[i], ".csv"))
    df$id<-paste0(df$chrom,"_",df$start)
    
    if (i!=3){
        #exact overlaps
        isec<-intersect(df$id[df$pop=="PWS"], df$id[df$pop=="TB"]) 
        Ov_direct$count[i]<-length(isec)
        
        #### Check chromosome region overlap +-200,000 bases
        pop1<-df[df$pop=="PWS",]
        pop2<-df[df$pop=="TB",]
        overlps<-data.frame()
        overlps2<-data.frame()
        for (n in 1: nrow(pop1)){
            re<-pop2[pop2$chrom==pop1$chrom[n],]
            if (nrow(re)>=1){
                for (s in 1: nrow(re)){
                    if (re$start[s]<=pop1$start[n]+200000 & re$start[s]>=pop1$start[n]-200000){
                        overlps<-rbind(overlps, re[s,])
                        overlps2<-rbind(overlps2,pop1[n,])}
                }
            }
        }
        # Merge two tables into one summary overlap table:
        ov<-data.frame(id=overlps$id)
        for (n in 1: nrow(overlps)){
            if (overlps$start[n]<overlps2$start[n]) {ov$start[n]<-overlps$start[n]; ov$end[n]<-overlps2$end[n]}
            if (overlps$start[n]>=overlps2$start[n]) {ov$start[n]<-overlps2$start[n];ov$end[n]<-overlps$end[n]}
        }
        ov[,"cov.PWS"]<-overlps[,4]
        ov[,"cov.TB"]<-overlps2[,4]
        write.csv(ov, paste0("../Output/COV/COVscan_3pop/cutoff/Overlap_regions_",cv[i],"_plusminus100k.csv"), row.names = F)
        Ov_300$count[i]<-nrow(ov)
        }
        
    if (i==3){
        isec<-intersect(df$id[df$pop=="PWS"], df$id[df$pop=="TB"]) 
        isec2<-intersect(df$id[df$pop=="PWS"], df$id[df$pop=="SS"]) 
        isec3<-intersect(df$id[df$pop=="SS"], df$id[df$pop=="TB"]) 
        Ov_direct$count[i]<-length(isec)
        Ov_direct$count[i+1]<-length(isec2)
        Ov_direct$count[i+2]<-length(isec3)
        Ov_direct$count[i+3]<-length(intersect(df$id[df$pop=="SS"], intersect(df$id[df$pop=="PWS"], df$id[df$pop=="TB"])))
        
        for(j in 1:nrow(pairs)){
        #### Check chromosome region overlap +-200,000 bases
            pop1<-df[df$pop==pairs[j,1],]
            pop2<-df[df$pop==pairs[j,2],]
            overlps<-data.frame()
            overlps2<-data.frame()
            for (n in 1: nrow(pop1)){
                re<-pop2[pop2$chrom==pop1$chrom[n],]
                if (nrow(re)>=1){
                    for (s in 1: nrow(re)){
                        if (re$start[s]<=pop1$start[n]+200000 & re$start[s]>=pop1$start[n]-200000){
                            overlps<-rbind(overlps, re[s,])
                            overlps2<-rbind(overlps2,pop1[n,])}
                    }
                }
            }
        # Merge two tables into one summary overlap table:
            ov<-data.frame(id=overlps$id)
            for (n in 1: nrow(overlps)){
                if (overlps$start[n]<overlps2$start[n]) {ov$start[n]<-overlps$start[n]; ov$end[n]<-overlps2$end[n]}
                if (overlps$start[n]>=overlps2$start[n]) {ov$start[n]<-overlps2$start[n];ov$end[n]<-overlps$end[n]}
            }
        
            ov[,paste0("cov.",pairs[j,1])]<-overlps[,4]
            ov[,paste0("cov.",pairs[j,2])]<-overlps2[,4]
            ov<-ov[!duplicated(ov),]
            write.csv(ov, paste0("../Output/COV/COVscan_3pop/cutoff/Overlap_regions_",cv[i],"_",pairs[j,1],".", pairs[j,2],"_plusminus200k.csv"), row.names = F)
            Ov_300$count[i+j-1]<-nrow(ov)
    }
    }
}
write.csv(Ov_direct, paste0("../Output/COV/COVscan_3pop/cutoff/Direct_Overlapping_regions_counts_3pop_summary.csv"))
Ov_300$count[6]<-NA
write.csv(Ov_300, paste0("../Output/COV/COVscan_3pop/cutoff/Overlapping_regions_counts_3pop_plusMinus200k.csv"))

4 Run the snpEff pipeline to find annotation in the outlier regions (100k-window+-100k)

4.1 Create a script to run SnpEff

Create VCF files with selected regions & run snpEff

#Create bed files
cv<-c("cov12","cov13","cov23")
#Prevent scientific notation in bed files
options(scipen=999)

#The first line of bed files is often not red by vcftools
for (i in 1:3){
    df<-read.csv(paste0("../Output/COV/COVscan_3pop/cutoff/3pops_top1percent_outlier_cutoff.", cv[i], ".csv"))
    #add 100k
    df$start<-df$start-100000
    df$end<-df$end+100000
    dfp<-df[df$pop=="PWS",1:3]
    colnames(dfp)<-c('track type=bedGraph', '1','1')
    write.table(dfp, paste0("../Output/COV/COVscan_3pop/cutoff/PWS_outliers_",cv[i],"_new.bed"),quote = F, row.names = F, col.names = T,sep = "\t")
    dft<-df[df$pop=="TB",1:3]
    colnames(dft)<-c('track type=bedGraph', '1','1')
    write.table(dft, paste0("../Output/COV/COVscan_3pop/cutoff/TB_outliers_",cv[i],"_new.bed"),quote = F, row.names = F, col.names = F,sep = "\t")
    
    if (i==3){
        dfs<-df[df$pop=="SS",1:3]
        colnames(dfs)<-c('track type=bedGraph', '1','1')
        write.table(dfs, paste0("../Output/COV/COVscan_3pop/cutoff/SS_outliers_",cv[i],"_new.bed"),quote = F, row.names = F, col.names = F,sep = "\t")
    }
}

# Create a bash script to create vcf files with selected regions
bedfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern="*_new.bed")

sink("../COVscan_createVCFs_3Pops_cutoff.sh")
cat("#!/bin/bash \n\n")
for (i in 1:length(bedfiles)){
    fname<-gsub(".bed",'', bedfiles[i])
    cat(paste0("vcftools --gzvcf Data/new_vcf/3pop/3pops.MD7000_NS0.5_maf05.vcf.gz --bed Output/COV/COVscan_3pop/cutoff/", bedfiles[i], " --out Output/COV/COVscan_3pop/cutoff/", fname," --recode --keep-INFO-all \n"))
}
sink(NULL)  

4.1.1 Create bed files and scripts to run SnpEff with less padded windows (10k)

Create VCF files with selected regions & run snpEff

#Create bed files
cv<-c("cov12","cov13","cov23")
#Prevent scientific notation in bed files
options(scipen=999)

#The first line of bed files is often not red by vcftools
for (i in 1:3){
    df<-read.csv(paste0("../Output/COV/COVscan_3pop/cutoff/3pops_top1percent_outlier_cutoff.", cv[i], ".csv"))
    #add 10k
    df$start<-df$start-10000
    df$end<-df$end+10000
    dfp<-df[df$pop=="PWS",1:3]
    colnames(dfp)<-c('track type=bedGraph', '1','1')
    write.table(dfp, paste0("../Output/COV/COVscan_3pop/cutoff/PWS_outliers_",cv[i],"_10kpad.bed"),quote = F, row.names = F, col.names = T,sep = "\t")
    dft<-df[df$pop=="TB",1:3]
    colnames(dft)<-c('track type=bedGraph', '1','1')
    write.table(dft, paste0("../Output/COV/COVscan_3pop/cutoff/TB_outliers_",cv[i],"_10kpad.bed"),quote = F, row.names = F, col.names = F,sep = "\t")
    
    if (i==3){
        dfs<-df[df$pop=="SS",1:3]
        colnames(dfs)<-c('track type=bedGraph', '1','1')
        write.table(dfs, paste0("../Output/COV/COVscan_3pop/cutoff/SS_outliers_",cv[i],"_10kpad.bed"),quote = F, row.names = F, col.names = F,sep = "\t")
    }
}

# Create a bash script to create vcf files with selected regions
bedfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern="*_10kpad.bed")

sink("../COVscan_createVCFs_3Pops_cutoff_10kpad.sh")
cat("#!/bin/bash \n\n")
for (i in 1:length(bedfiles)){
    fname<-gsub(".bed",'', bedfiles[i])
    cat(paste0("vcftools --gzvcf Data/new_vcf/3pop/3pops.MD7000_NS0.5_maf05.vcf.gz --bed Output/COV/COVscan_3pop/cutoff/", bedfiles[i], " --out Output/COV/COVscan_3pop/cutoff/", fname," --recode --keep-INFO-all \n"))
}
sink(NULL)  
#create a bash script to run snpEff
vfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern=".recode.vcf")

sink("~/programs/snpEff/runsnpEff_cov_3pop_cutoff.sh")
cat("#!/bin/bash \n\n")
for (i in 1:length(vfiles)){
    fname<-gsub("_new.recode.vcf","",vfiles[i])
    cat(paste0("java -Xmx8g -jar snpEff.jar Ch_v2.0.2.99 ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/",vfiles[i], " -stats ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/",fname,".html >  ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/Anno.",fname,".vcf \n"))
    
    #extract the annotation information
    cat(paste0("bcftools query -f '%CHROM %POS %INFO/AF %INFO/ANN\\n' ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/Anno.",fname,".vcf > ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/",fname,"_annotation \n\n"))

}
sink(NULL)  


## for 10k pad vcf

#create a bash script to run snpEff
vfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern="10kpad.recode.vcf")

sink("~/programs/snpEff/runsnpEff_cov_3pop_cutoff_10kpad.sh")
cat("#!/bin/bash \n\n")
for (i in 1:length(vfiles)){
    fname<-gsub(".recode.vcf","",vfiles[i])
    cat(paste0("java -Xmx8g -jar snpEff.jar Ch_v2.0.2.99 ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/",vfiles[i], " -stats ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/",fname,".html >  ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/Anno.",fname,".vcf \n"))
    
    #extract the annotation information
    cat(paste0("bcftools query -f '%CHROM %POS %INFO/AF %INFO/ANN\\n' ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/Anno.",fname,".vcf > ~/Projects/PacHerring/Output/COV/COVscan_3pop/cutoff/",fname,"_annotation \n\n"))

}
sink(NULL)  

4.2 Create summary gene files from snpEff and check overlapping genes.

## Create summary files of snpEff results (gene annotations in the regions of interest) and reformat as a ShinyGo input 

#create gene list 
gfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern="genes.txt")

for (i in 1:length(gfiles)){
    df<-read.table(paste0("../Output/COV/COVscan_3pop/cutoff/",gfiles[i]), sep="\t")
    df<-df[,1:7]
    colnames(df)<-c("GeneName","GeneId","TranscriptId","BioType","variants_impact_HIGH","variants_impact_LOW",  "variants_impact_MODERATE")
    
    fname<-gsub(".genes.txt","",gfiles[i])
    genes<-unique(df$GeneId)
    sink(paste0("../Output/COV/COVscan_3pop/cutoff/geneIDlist_",fname,".txt"))
    cat(paste0(genes,"; "))
    sink(NULL)
}

#Annotation infor from SnpEff
cv<-c("cov12","cov13","cov23")
for (c in 1:3){
    if (c!=3){
    for (p in 1:2){
        ano<-read.table(paste0("../Output/COV/COVscan_3pop/cutoff/",pops[p],"_outliers_",cv[c],"_annotation"), header = F)
        annotations<-data.frame()
        for (i in 1: nrow(ano)){
            anns<-unlist(strsplit(ano$V4[i], "\\,|\\|"))
            annm<-data.frame(matrix(anns,ncol = 16, byrow = TRUE))
            annm<-annm[,c(2,3,4,5,8)]
            colnames(annm)<-c("Effect","Putative_impact","Gene_name","Gene_ID","Feature type")
            annm<-annm[!duplicated(annm), ]
            annm$chr<-ano$V1[i]
            annm$pos<-ano$V2[i]
            annm$AF<- ano$V3[i]
            annotations<-rbind(annotations, annm)
        }     
        annotations<-annotations[,c(6:8,1:5)]
        annotations<-annotations[!duplicated(annotations[,1:2]),]
        write.csv(annotations, paste0("../Output/COV/COVscan_3pop/cutoff/Genes_",pops[p],"_outliers_100k_",cv[c],".csv"), row.names = F)
    }
    }
    if (c==3){
        for (p in 1:3){
        ano<-read.table(paste0("../Output/COV/COVscan_3pop/cutoff/",pops[p],"_outliers_",cv[c],"_annotation"), header = F)
        annotations<-data.frame()
        for (i in 1: nrow(ano)){
            anns<-unlist(strsplit(ano$V4[i], "\\,|\\|"))
            annm<-data.frame(matrix(anns,ncol = 16, byrow = TRUE))
            annm<-annm[,c(2,3,4,5,8)]
            colnames(annm)<-c("Effect","Putative_impact","Gene_name","Gene_ID","Feature type")
            annm<-annm[!duplicated(annm), ]
            annm$chr<-ano$V1[i]
            annm$chr<-ano$V1[i]
            annm$pos<-ano$V2[i]
            annm$AF<- ano$V3[i]
            annotations<-rbind(annotations, annm)
        }     
        annotations<-annotations[,c(6:8,1:5)]
        annotations<-annotations[!duplicated(annotations[,1:2]),]
        write.csv(annotations, paste0("../Output/COV/COVscan_3pop/cutoff/Genes_",pops[p],"_outliers_100k_",cv[c],".csv"), row.names = F)
    }
}
  
}

4.2.1 for 10k pad data

## Create summary files of snpEff results (gene annotations in the regions of interest) and reformat as a ShinyGo input 

#create gene list 
gfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern="10kpad.genes.txt")
for (i in 1:length(gfiles)){
    df<-read.table(paste0("../Output/COV/COVscan_3pop/cutoff/",gfiles[i]), sep="\t")
    df<-df[,1:7]
    colnames(df)<-c("GeneName","GeneId","TranscriptId","BioType","variants_impact_HIGH","variants_impact_LOW",  "variants_impact_MODERATE")
    
    fname<-gsub(".genes.txt","",gfiles[i])
    genes<-unique(df$GeneId)
    sink(paste0("../Output/COV/COVscan_3pop/cutoff/geneIDlist_",fname,".txt"))
    cat(paste0(genes,"; "))
    sink(NULL)
}


### no enrichment found from 10k pad (PWS-cov12)

4.3 Find the overlapping gene names

gnamesfiles<-list.files("../Output/COV/COVscan_3pop/cutoff/", pattern="Genes_.+outliers_100k.+\\d.csv$")

for (i in 1:length(gnamesfiles)){
    df<-read.csv(paste0("../Output/COV/COVscan_3pop/cutoff/",gnamesfiles[i]))
    df<-df[,c(1,6:7)]
    df<-df[!duplicated(df),]
    
    fname<-gsub(".csv","", gnamesfiles[i])
    fname<-gsub("Genes_","", fname)
    
    
    #add gene names for front and back of intergenic regions
    df2<-df[grep("-", df$Gene_ID),]
    k=1
    df_div<-data.frame()
    oddnames<-data.frame()
    for (j in 1:nrow(df2)){
        names<-unlist(strsplit(df2$Gene_name[j], "-"))
        ids<-unlist(strsplit(df2$Gene_ID[j], "-"))
        
        if (length(names)==2){
            df_div<-rbind(df_div, c(df2$chr[j],names[1],ids[1]))
            k=k+1
            df_div<-rbind(df_div, c(df2$chr[j],names[2],ids[2]))
            k=k+1
        }
       
        if (length(names)!=2){
            n<-grep("si:", names)
            if (length(n)>0){
                if (n==1) newnames<-c(paste0(names[1],"-",names[2]), names[3])
                if (n==2) newnames<-c(names[1],paste0(names[2],"-",names[3]))
                df_div<-rbind(df_div, c(df2$chr[j],newnames[1],ids[1]))
                k=k+1
                df_div<-rbind(df_div, c(df2$chr[j],newnames[2],ids[2]))
                k=k+1
            }
            
            if (length(n)==0) {
                oddnames<-rbind(oddnames, df2[j,])
            }
        }
    }
    df_div<-df_div[!duplicated(df_div),]
    df_div<-df_div[df_div$Gene_ID!="CHR_END",]
    df_div<-df_div[df_div$Gene_ID!="CHR_START",]
    
    remove<-grep("-", df$Gene_ID)
    df<-df[-remove,]
    df<-rbind(df, df_div)
    df<-df[!duplicated(df),]
    
    if (nrow(oddnames)!=0){
        write.csv(df, paste0("../Output/COV/COVscan_3pop/cutoff/",fname,"GeneList_withIntergenicGenes.csv" ), row.names = F)
        write.csv(oddnames, paste0("../Output/COV/COVscan_3pop/cutoff/Oddnames_", fname,".csv"))
    }
    if (nrow(oddnames)==0){
        write.csv(df, paste0("../Output/COV/COVscan_3pop/cutoff/",fname,"GeneList_withIntergenicGenes_new.csv" ), row.names = F)
     }
}
   

## !! ##
## Manually change the oddnames and add them to the GeneList (XX.GeneList_withIntergenicGenes.csv) files 
# Add the gene IDs to geneIDlist_XX_outliers_covxx.txt files as well -only one needs to be updated is TB cov13
#(updated file names has "_new" at the end)

#aggregate all gene names
gnew<-list.files("../Output/COV/COVscan_3pop/", pattern="GeneList_withIntergenicGenes_new.csv$")
Genes<-data.frame()
GeneList<-list()
for (i in 1:length(gnew)){
    df<-read.csv(paste0("../Output/COV/COVscan_3pop/", gnew[i]))
    GeneList[[i]]<-df
    fname<-gsub("GeneList_withIntergenicGenes_new.csv",'',gnew[i])
    names(GeneList)[i]<-fname
    dup<-df[duplicated(df),]
    df<-df[!duplicated(df),]
    Genes<-rbind(Genes, df)
    Genes<-Genes[!duplicated(Genes),]
    
}


#1. Between populations
times<-c("cov12","cov13","cov23")
common<-list()
common_summary<-data.frame(time=times)
for (i in 1:3){
    tlist<-GeneList[grep(times[i], names(GeneList))]
    if (i !=3){
        common_genes<-intersect(tlist[[1]]["Gene_name"], tlist[[2]]["Gene_name"])
        common[[i]]<-common_genes
        names(common)[[i]]<-times[i]
        common_summary$PWS[i]<-nrow(tlist[[grep("PWS", names(tlist))]])
        common_summary$TB[i]<-nrow(tlist[[grep("TB", names(tlist))]])
        common_summary$SS[i]<-NA
        common_summary$common_PWS.TB[i]<-nrow(common_genes)
        
        pws<-tlist[[1]]["Gene_name"]
        tb<-tlist[[2]]["Gene_name"]
        x<-list(PWS=pws$Gene_name,TB=tb$Gene_name)
        ggvenn(x, fill_color = cols[c(2,1)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle(times[i])
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_",times[i],".png"), width = 3, height=3, dpi=300)
    }
    if (i==3){
        common_summary$PWS[i]<-nrow(tlist[[grep("PWS", names(tlist))]])
        common_summary$TB[i]<- nrow(tlist[[grep("TB", names(tlist))]])
        common_summary$SS[i]<- nrow(tlist[[grep("SS", names(tlist))]])
        
        genes1<-intersect(tlist[[1]]["Gene_name"], tlist[[3]]["Gene_name"])
        genes2<-intersect(tlist[[1]]["Gene_name"], tlist[[2]]["Gene_name"])
        genes3<-intersect(tlist[[2]]["Gene_name"], tlist[[3]]["Gene_name"])
        genes4<-intersect(tlist[[1]]["Gene_name"],intersect(tlist[[2]]["Gene_name"], tlist[[3]]["Gene_name"]))
        common_summary$common_PWS.TB[i]<-nrow(genes1)
        common_summary$common_PWS.SS[i]<-nrow(genes2)
        common_summary$common_SS.TB[i]<-nrow(genes3)
        common_summary$common3[i]<-nrow(genes4)
        k=i
        common[[k]]<-genes2
        names(common)[[k]]<-paste0(times[i],"_PWS.SS")
        k=k+1
        common[[k]]<-genes1
        names(common)[[k]]<-paste0(times[i],"_PWS.TB")
        k=k+1
        common[[k]]<-genes3
        names(common)[[k]]<-paste0(times[i],"_SS.TB")
        k=k+1
        common[[k]]<-genes4
        names(common)[[k]]<-paste0(times[i],"_3pops")
        
        pws<-tlist[[1]]["Gene_name"]
        tb<-tlist[[3]]["Gene_name"]
        ss<-tlist[[2]]["Gene_name"]
        x<-list(PWS=pws$Gene_name,TB=tb$Gene_name, SS=ss$Gene_name)
        ggvenn(x, fill_color = cols[c(2,1,3)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle(times[i])
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_",times[i],".png"), width = 4, height=4, dpi=300)
        
         x1<-list(PWS=pws$Gene_name,TB=tb$Gene_name)
        ggvenn(x1, fill_color = cols[c(2,1)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle(times[i])
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_PWS_TB_",times[i],".png"), width = 3, height=3, dpi=300)
         x2<-list(PWS=pws$Gene_name,SS=ss$Gene_name)
        ggvenn(x2, fill_color = cols[c(2,3)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle(times[i])
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_PWS_SS_",times[i],".png"), width = 3, height=3, dpi=300)
          x3<-list(SS=ss$Gene_name, TB=tb$Gene_name)
        ggvenn(x3, fill_color = cols[c(3,1)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle(times[i])
        ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_SS_TB_",times[i],".png"), width = 3, height=3, dpi=300)
        
        
        }
}
write.csv(common_summary, "../Output/COV/COVscan_3pop/cutoff/Common_genes_withIntergenes_3pops.csv")


#What are the overlapping gene names between populations
common_times<-list()
for (i in 1: length(common)){
    gids<-common[[i]]
    df<-data.frame(Gene_name=gids)
    
    df2<-merge(df, Genes, by="Gene_name")
    write.csv(df2, paste0("../Output/COV/COVscan_3pop/cutoff/Common_genes_", names(common)[i],".csv"), row.names = F)
    common_times[[i]]<-df2
    names(common_times)[i]<- names(common)[i]
}


#overlapping genes COV12

tlist<-GeneList[grep(times[1], names(GeneList))]
genes1<-intersect(tlist[[1]]["Gene_ID"], tlist[[2]]["Gene_ID"]) #common genes between PWS and TB in cov12
g1<-unique(genes1$Gene_ID)
sink("../Output/COV/COVscan_3pop/cutoff/overlapping_genes/geneIDs_PWS_TB_cov12.txt")
cat(paste0(g1, ";"))
sink(NULL)

# Overlapping genes COV13

tlist<-GeneList[grep(times[2], names(GeneList))]
genes1<-intersect(tlist[[1]]["Gene_ID"], tlist[[2]]["Gene_ID"]) #common genes between PWS and TB in cov12
g1<-unique(genes1$Gene_ID)
sink("../Output/COV/COVscan_3pop/cutoff/overlapping_genes/geneIDs_PWS_TB_cov13.txt")
cat(paste0(g1, ";"))
sink(NULL)




#overlapping genes COV23

tlist<-GeneList[grep(times[3], names(GeneList))]
pws23<-tlist[[1]]["Gene_ID"]
ss23<-tlist[[2]]["Gene_ID"]
tb23<-tlist[[3]]["Gene_ID"]
genes1<-intersect(tlist[[1]]["Gene_ID"], tlist[[3]]["Gene_ID"]) #common genes between PWS and TB in cov23
genes2<-intersect(tlist[[1]]["Gene_ID"], tlist[[2]]["Gene_ID"]) #common genes between PWS and SS in cov23
genes3<-intersect(tlist[[2]]["Gene_ID"], tlist[[3]]["Gene_ID"]) #common genes between SS and TB in cov23
genes4<-intersect(tlist[[1]]["Gene_ID"],intersect(tlist[[2]]["Gene_ID"], tlist[[3]]["Gene_ID"])) # Common genes in all 3 populations
g1<-unique(genes1$Gene_ID)
sink("../Output/COV/COVscan_3pop/cutoff/overlapping_genes/geneIDs_PWS_TB_cov23.txt")
cat(paste0(g1, ";"))
sink(NULL)

g2<-unique(genes2$Gene_ID)
sink("../Output/COV/COVscan_3pop/cutoff/overlapping_genes/geneIDs_PWS_SS_cov23.txt")
cat(paste0(g2, ";"))
sink(NULL)

g3<-unique(genes3$Gene_ID)
sink("../Output/COV/COVscan_3pop/cutoff/overlapping_genes/geneIDs_SS_TB_cov23.txt")
cat(paste0(g3, ";"))
sink(NULL)

g4<-unique(genes4$Gene_ID)
sink("../Output/COV/COVscan_3pop/cutoff/overlapping_genes/geneIDs_all3_cov23.txt")
cat(paste0(g4, ";"))
sink(NULL)



#2. Between Time-Points within a population

times<-c("cov12","cov13","cov23")
pops<-c("PWS","TB")
common2<-list()
common_summary2<-data.frame(pop=rep(pops[1:2], each=4))
for (i in 1:length(pops)){
    plist<-GeneList[grep(pops[i], names(GeneList))]
    k=4*i-3
    #common genes between COV12 and COV13
    common_genes1<-intersect(plist[[1]]["Gene_name"], plist[[2]]["Gene_name"])
    common2[[k]]<-common_genes1
    names(common2)[[k]]<-paste0(pops[i],".", times[1],"_",times[2])
    common_summary2$Time[k]<-paste0(times[1],"_",times[2])
    common_summary2$no.of.genes[k]<-nrow(common_genes1) 
    
    c12<-plist[[1]]["Gene_name"]
    c13<-plist[[2]]["Gene_name"]
    c23<-plist[[3]]["Gene_name"]
    x<-list(COV12=c12$Gene_name,COV13=c13$Gene_name, COV23=c23$Gene_name)
    ggvenn(x, fill_color = cols[c(1,5,7)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle(pops[i])
    ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_",pops[i],".png"), width = 4, height=4, dpi=300)

    
    k=k+1
    #common genes between COV12 and COV23
    common_genes2<-intersect(plist[[1]]["Gene_name"], plist[[3]]["Gene_name"])
    common2[[k]]<-common_genes2
    names(common2)[[k]]<-paste0(pops[i],".", times[1],"_",times[3])
    common_summary2$Time[k]<-paste0(times[1],"_",times[3])
    common_summary2$no.of.genes[k]<-nrow(common_genes2) 
 
    k=k+1
    #common genes between COV13 and COV23
    common_genes3<-intersect(plist[[2]]["Gene_name"], plist[[3]]["Gene_name"])
    common2[[k]]<-common_genes3
    names(common2)[[k]]<-paste0(pops[i],".", times[2],"_",times[3])
    common_summary2$Time[k]<-paste0(times[2],"_",times[3])
    common_summary2$no.of.genes[k]<-nrow(common_genes3) 
 
    k=k+1
    #common genes among all time periods
    common_genes4<-intersect(plist[[1]]["Gene_name"], (intersect(plist[[2]]["Gene_name"], plist[[3]]["Gene_name"])))
    common2[[k]]<-common_genes4
    names(common2)[[k]]<-paste0(pops[i],".all")
    common_summary2$Time[k]<-"All"
    common_summary2$no.of.genes[k]<-nrow(common_genes4) 
}
write.csv(common_summary2, "../Output/COV/COVscan_3pop/cutoff/Common_genes_betweenTimePoints.csv")


#Common gene names between time points

for (i in 1:2){
    CommonGenes<-data.frame()
    glist<-common2[grep(pops[i], names(common2))]
    for(j in 1:length(glist)){
        gids<-glist[[j]]
        df<-data.frame(Gene_name=gids)
        df2<-merge(df, Genes, by="Gene_name", all.x=T)
        write.csv(df2, paste0("../Output/COV/COVscan_3pop/cutoff/Common_genes_", names(glist)[j],".csv"), row.names = F)
        df2$Time<-names(glist)[j]
        CommonGenes<-rbind(CommonGenes, df2)
    }
    write.csv(CommonGenes, paste0("../Output/COV/COVscan_3pop/cutoff/Common_genes_",pops[i] ,".csv"), row.names = F)
}

4.3.0.1 Overlapping gene numbers


# Summary table
common_genes<-read.csv("../Output/COV/COVscan_3pop/cutoff/Common_genes_withIntergenes_3pops.csv", row.names = 1)
knitr::kable(common_genes)

4.4 What are the genes overlapping across different time points between populations?

## Between PWS and TB
pws.tb<-common_times[c(1,2,4)]

# 1. Common genes between populations across time points in PWS and TB (COV12 - COV13)
genes1213<-intersect(pws.tb[[1]]["Gene_name"], pws.tb[[2]]["Gene_name"])
genes1213<-merge(genes1213, Genes, by="Gene_name")
write.csv(genes1213, "../Output/COV/COVscan_3pop/cutoff/Common_genes_PWS.TB.cov12-cov23.csv")
#           Gene_name   chr            Gene_ID
#1 ENSCHAG00000001687 chr13 ENSCHAG00000001687
#2             ndst2a chr13 ENSCHAG00000002649
#3             zswim8 chr13 ENSCHAG00000005956

#common gene names
p1213<-pws.tb[[1]]["Gene_name"]
t1213<-pws.tb[[2]]["Gene_name"]
x<-list(PWS=p1213$Gene_name,TB=t1213$Gene_name)
ggvenn(x, fill_color = cols[c(2,1)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("COV12-COV13 in PWS & TB")
ggsave(paste0("../Output/COV/COVscan_3pop/Venn_PWS_TB_COV12-COV13.png"), width = 3, height=3, dpi=300)
        

# 2. Common genes between populations across time points in PWS and TB (COV12 - COV23)

genes1223<-intersect(pws.tb[[1]]["Gene_name"], pws.tb[[3]]["Gene_name"])
genes1223<-merge(genes1223, Genes, by="Gene_name")
write.csv(genes1223, "../Output/COV/COVscan_3pop/cutoff/Common_genes_PWS.TB.cov12-cov13.csv")
#           Gene_name   chr            Gene_ID
#1 ENSCHAG00000001687 chr13 ENSCHAG00000001687
#2 ENSCHAG00000022709 chr20 ENSCHAG00000022709
#3 ENSCHAG00000022815 chr20 ENSCHAG00000022815
#4             ndst2a chr13 ENSCHAG00000002649

p1223<-pws.tb[[1]]["Gene_name"]
t1223<-pws.tb[[3]]["Gene_name"]
x<-list(PWS=p1223$Gene_name,TB=t1223$Gene_name)
ggvenn(x, fill_color = cols[c(2,1)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("COV12-COV23 in PWS & TB")
ggsave(paste0("../Output/COV/COVscan_3pop/cutoff/Venn_PWS_TB_COV12-COV23.png"), width = 3, height=3, dpi=300)


# 3. between PWS and TB across COV13 and COV23
genes1323<-intersect(pws.tb[[2]]["Gene_name"], pws.tb[[3]]["Gene_name"])
genes1323<-merge(genes1323, Genes, by="Gene_name")
write.csv(genes1323, "../Output/COV/COVscan_3pop/cutoff/ommon_genes_PWS.TB.cov13-cov23.csv")
#           Gene_name   chr            Gene_ID
#1 ENSCHAG00000001687 chr13 ENSCHAG00000001687
#2             ndst2a chr13 ENSCHAG00000002649

p1323<-pws.tb[[2]]["Gene_name"]
t1323<-pws.tb[[3]]["Gene_name"]
x<-list(PWS=p1323$Gene_name,TB=t1323$Gene_name)
ggvenn(x, fill_color = cols[c(2,1)], stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("COV13-COV23 in PWS & TB")
ggsave("../Output/COV/COVscan_3pop/cutoff/Venn_PWS_TB_COV13-COV23.png", width = 3, height=3, dpi=300)
  • Numbers of overlapping genes between populations between time points

5 Interpopulation comparison per time period

### Interpopulation comparisons
#decode the samples to create the right matrix
cv<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_3pops.csv", header = F)
labs<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_labels_3pops.csv" )
labs<-labs[,-1]
cvm<-data.frame(label=as.vector(t(labs)), cov=as.vector(t(cv)))

#rearrange based on comparions: covariance between populations within the same period
#PopYr Symbols
# PH 1 'PWS', 1991
# PH 2 'PWS', 1996
# PH 3 'PWS', 2006
# PH 4 'PWS', 2017
# PH 5 'SS',  1991
# PH 6 'SS',  1996
# PH 7 'SS',  2006
# PH 8 'SS',  2017
# PH 9 'TB',  1991
# PH 10'TB',  1996
# PH 11'TB',  2006
# PH 12'TB',  2017

Covs<-data.frame(pops=rep(c("PWS.vs.SS", "PWS.vs.TB",  "SS.vs.TB"), times=6),
                 period=c(rep("1991-1996", times=3),rep("1996-2006", times=3), rep("2006-2017", times=3)))

Covs$cov<-c(NA, cvm$cov[cvm$label=="cov(PH: 2-1, PH: 10-9)"],NA,
            cvm$cov[cvm$label=="cov(PH: 3-2, PH: 7-6)"],cvm$cov[cvm$label=="cov(PH: 3-2, PH: 11-10)"], 
            cvm$cov[cvm$label=="cov(PH: 7-6, PH: 11-10)"],
            cvm$cov[cvm$label=="cov(PH: 4-3, PH: 8-7)"],cvm$cov[cvm$label=="cov(PH: 4-3, PH: 12-11)"],cvm$cov[cvm$label=="cov(PH: 8-7, PH: 12-11)"])



#C.I.
cis<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_COV_Interpop_comparison_CIs.csv")
cis<-cis[,-1]
cim<-data.frame(label=as.vector(t(labs)), ci_l=as.vector(t(cis[1:11,])))
cim$ci_h<-as.vector(t(cis[12:22,]))

Covs$ci_l<-as.numeric(c(NA,cim$ci_l[cim$label=="cov(PH: 2-1, PH: 10-9)"],NA,
                      cim$ci_l[cim$label=="cov(PH: 3-2, PH: 7-6)"],cim$ci_l[cim$label=="cov(PH: 3-2, PH: 11-10)"], cim$ci_l[cim$label=="cov(PH: 7-6, PH: 11-10)"],
                      cim$ci_l[cim$label=="cov(PH: 4-3, PH: 8-7)"],cim$ci_l[cim$label=="cov(PH: 4-3, PH: 12-11)"], cim$ci_l[cim$label=="cov(PH: 8-7, PH: 12-11)"]))

Covs$ci_h<-as.numeric(c(NA, cim$ci_h[cim$label=="cov(PH: 2-1, PH: 10-9)"],NA,
                      cim$ci_h[cim$label=="cov(PH: 3-2, PH: 7-6)"],cim$ci_h[cim$label=="cov(PH: 3-2, PH: 11-10)"], cim$ci_h[cim$label=="cov(PH: 7-6, PH: 11-10)"],
                      cim$ci_h[cim$label=="cov(PH: 4-3, PH: 8-7)"],cim$ci_h[cim$label=="cov(PH: 4-3, PH: 12-11)"], cim$ci_h[cim$label=="cov(PH: 8-7, PH: 12-11)"]))


library(RColorBrewer)
display.brewer.all(type="qual")

colors2<-brewer.pal(n=8, "Set3")
"#8DD3C7" "#FFFFB3" "#BEBADA" "#FB8072" "#80B1D3" "#FDB462" "#B3DE69" "#FCCDE5"

#Barplot
ggplot(Covs, aes(x=period, y=cov, fill=pops))+
    geom_bar(stat="identity",position=position_dodge(width = 0.7), width=0.8)+
    ylab("Covariance")+xlab('')+theme_classic()+
    geom_hline(yintercept = 0,color="gray70", size=0.3)+
    scale_fill_manual(values=colors2[c(4,1,3)])+
    theme(legend.title = element_blank())+
    scale_y_continuous(labels = comma)+
    ylim(-0.0013, 0.002)+
    geom_vline(xintercept = c(1.5,2.5), color="gray", size=0.2)+
    geom_errorbar(aes(ymin=ci_l, ymax=ci_h), width=.2, size=.2, position=position_dodge(width = 0.7))
ggsave("../Output/COV/Interpop_cov_comparison_3Pops_new.png",width = 4.8, height = 3, dpi=300)

#Point plot
ggplot(Covs, aes(x=period, y=cov, color=pops))+
    geom_point(position=position_dodge(width = 0.7), size=3)+
    ylab("Covariance")+xlab('')+theme_classic()+
    geom_hline(yintercept = 0,color="gray70", size=0.3)+
    scale_color_manual(values=colors2[c(4,1,3)])+
    theme(legend.title = element_blank())+
    scale_y_continuous(labels = comma)+
    geom_errorbar(aes(ymin=ci_l, ymax=ci_h), width=.2, size=.2, position=position_dodge(width = 0.7))+
    ylim(-0.0023, 0.002)+
     geom_vline(xintercept = c(1.5,2.5), color="gray", size=0.3)
ggsave("../Output/COV/Interpop_cov_comparison_3Pops_new_PointPlot.png",width = 4.8, height = 3, dpi=300)



#line plot
Covs$time<-1
Covs$time[Covs$period=="1996-2006"]<-2
Covs$time[Covs$period=="2006-2017"]<-3
Covs<-Covs[order(Covs$time),]
ggplot(Covs, aes(x=time, y=cov, color=pops, group=pops))+
    geom_point(position=position_dodge(width = 0.7), size=4)+
    geom_path(position=position_dodge(width = 0.7))+
    ylab("Covariance")+xlab('')+theme_classic()+
    geom_hline(yintercept = 0,color="gray70", size=0.3)+
    scale_color_manual(values=colors2[c(4,1,3)])+
    theme(legend.title = element_blank())+
    scale_y_continuous(labels = comma)+
    geom_errorbar(aes(ymin=ci_l, ymax=ci_h), width=.2, size=.2, position=position_dodge(width = 0.7))+
    ylim(-0.0023, 0.002)+
     geom_vline(xintercept = c(1.5,2.5), color="gray", size=0.2)+
    scale_x_continuous(breaks=c(1,2,3), labels = c("1991-1996","1996-2006","2006-2017"))
ggsave("../Output/COV/Interpop_cov_comparison_3Pops_new_LinePlot.png",width = 4.8, height = 3, dpi=300)

5.1 Longer time period

## Longer time-period
Covs2<-data.frame(pops=rep(c("PWS.vs.SS", "PWS.vs.TB",  "SS.vs.TB"), times=3),
                 period=c(rep("1991-2006", times=3),rep("1991-2017", times=3),rep("1996-2017", times=3)))

cv1<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_1991-2006.csv", header = F)
labs1<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_labels_1991-2006.csv" )
labs1<-labs1[,-1]
cvm1<-data.frame(label=as.vector(t(labs1)), cov=as.vector(t(cv1)))

cv2<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_1991-2017.csv", header = F)
labs2<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_labels_1991-2017.csv" )
labs2<-labs2[,-1]
cvm2<-data.frame(label=as.vector(t(labs2)), cov=as.vector(t(cv2)))

cv3<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_1996-2017.csv", header = F)
labs3<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_Covs_interPopulations_100k_labels_1996-2017.csv" )
labs3<-labs3[,-1]
cvm3<-data.frame(label=as.vector(t(labs3)), cov=as.vector(t(cv3)))

Covs2$cov<-c(NA, cvm1$cov[cvm1$label=="cov(PH: 2-1, PH: 4-3)"], NA,
             NA, cvm2$cov[cvm2$label=="cov(PH: 2-1, PH: 4-3)"], NA,
             cvm3$cov[cvm3$label=="cov(PH: 2-1, PH: 4-3)"], cvm3$cov[cvm3$label=="cov(PH: 2-1, PH: 6-5)"], cvm3$cov[cvm3$label=="cov(PH: 4-3, PH: 6-5)"])

#C.I.
cis1<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_COV_Interpop_comparison_CIs_1991-2006.csv")
cis1<-cis1[,-1]
cis2<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_COV_Interpop_comparison_CIs_1991-2017.csv")
cis2<-cis2[,-1]
cis3<-read.csv("~/Projects/Pacherring_Vincent/MD7000/GW_COV_Interpop_comparison_CIs_1996-2017.csv")
cis3<-cis3[,-1]

#cim<-data.frame(label=as.vector(t(labs)), ci_l=as.vector(t(cis1[1:4,])))
#cim$ci_h<-as.vector(t(cis[12:22,]))

Covs2$ci_l<-as.numeric(c(NA,cis1[1,3],NA,
                        NA,cis2[1,3],NA,
                      cis3[1,3],cis3[1,5],cis3[3,5]))

Covs2$ci_h<-as.numeric(c(NA,cis1[4,3],NA,
                        NA,cis2[4,3],NA,
                      cis3[6,3],cis3[6,5],cis3[8,5]))


ggplot(Covs2, aes(x=period, y=cov, fill=pops))+
    geom_bar(stat="identity",position=position_dodge(width = 0.7), width=0.8)+
    ylab("Covariance")+xlab('')+theme_classic()+
    geom_hline(yintercept = 0,color="gray70", size=0.3)+
    scale_fill_manual(values=colors2[c(4,1,3)])+
    theme(legend.title = element_blank())+scale_y_continuous(labels = comma)+
    ylim(-0.0013, 0.002)+geom_vline(xintercept = c(1.5,2.5), color="gray", size=0.2)+
    geom_errorbar(aes(ymin=ci_l, ymax=ci_h), width=.2, size=.2, position=position_dodge(width = 0.7))
ggsave("../Output/COV/Interpop_cov_comparison_3Pops_LonogerPeriod.png",width = 4.9, height = 3, dpi=300)

ggplot(Covs2, aes(x=period, y=cov, color=pops))+
    geom_point(position=position_dodge(width = 0.7), size=4)+
    ylab("Covariance")+xlab('')+theme_classic()+
    geom_hline(yintercept = 0,color="gray70", size=0.3)+
    scale_color_manual(values=colors2[c(4,1,3)])+
    theme(legend.title = element_blank())+
    scale_y_continuous(labels = comma)+
     ylim(-0.0013, 0.002)+
    geom_errorbar(aes(ymin=ci_l, ymax=ci_h), width=.2, size=.2, position=position_dodge(width = 0.7))+
    geom_vline(xintercept = c(1.5,2.5), color="gray", size=0.3)
ggsave("../Output/COV/Interpop_cov_comparison_3PopsLonogerPeriod_PointPlot.png",width = 4.7, height = 3, dpi=300)

6 Focused freq analysis

6.1 ccr6a (chr15: 16,066,502 - 16,091,639)

pops<-c("PWS91","PWS96","PWS07","PWS17")
yr<-c(1991,1996,2007,2017)
maf<-data.frame()
for (i in 1:4){
    af<-read.table(paste0("../Data/new_vcf/AF/",pops[i],".mafs"),sep="\t", header = T)
    af<-af[af$chromo=="chr15"&af$position>=16050000&af$position<=16100000,]
    af$year<-yr[i]
    maf<-rbind(maf,af)
}
write.csv(maf,"../Output/COV/COVscan_3pop/cutoff/ccrc6_MAFchange_chr15_16Mb.csv")

positions<-unique(maf$position)
for (i in 1:length(positions)){
    df<-maf[maf$position==positions[i],]
    #AF both decreased
    if (df$knownEM[df$year==1991]>df$knownEM[df$year==1996] & df$knownEM[df$year==1996]>df$knownEM[df$year==2007]){
        maf$trend[maf$position==positions[i]]<-"down"
    }
    else if (df$knownEM[df$year==1991]<df$knownEM[df$year==1996] & df$knownEM[df$year==1996]<df$knownEM[df$year==2007]){
        maf$trend[maf$position==positions[i]]<-"up"
    }
    
    else maf$trend[maf$position==positions[i]]<-"none"
}

write.csv(maf,"../Output/COV/COVscan_3pop/cutoff/ccrc6_MAFchange_chr15_16Mb.csv")

ggplot(maf, aes(x=year, y=knownEM, color=factor(position)))+
    geom_point(size=1.5)+
    geom_line(size=0.3)+ggtitle("CCRC6 gene AF changes")+
    ylab("maf")+
    theme(legend.title=element_blank())+
    theme_minimal()+theme(legend.text = element_text(size=5), legend.title=element_blank())
ggsave("../Output/COV/COVscan_3pop/cutoff/PWS_ccr6c_AFchange_ch15.png", width = 6, height=3, dpi=300)

#color by trend
maf$trend<-factor(maf$trend, levels=c("up","down","none"))
ggplot(maf, aes(x=year, y=knownEM, color=trend))+
    geom_point(size=1.5)+
    geom_path(aes(group=position), size=0.3)+ggtitle("CCRC6 gene AF changes 1991-2007")+
    ylab("maf")+
    theme(legend.title=element_blank())+
    theme_minimal()+theme(legend.title=element_blank())+
    scale_color_manual("Trend",values=c("deeppink2","royalblue", "gray"))
ggsave("../Output/COV/COVscan_3pop/cutoff/PWS_ccr6c_AFchange_ch15_trend.png", width = 6, height=3, dpi=300)

up<-maf[maf$trend=="up",]
down<-maf[maf$trend=="down",]
library(ggrepel)

# Plot separately

up<-up %>% mutate(label = if_else(year == max(year), as.character(position), NA_character_))
ggplot(up, aes(x=year, y=knownEM))+
    geom_point(size=1.5,color="deeppink2", alpha=0.8)+
    geom_path(aes(group=position), size=0.3,color="deeppink2" )+ggtitle(paste0("CCRC6 AF changes 1991-2007, Up ",length((unique(maf$position[maf$trend=="up"])))," loci"))+
    ylab("maf")+
    theme(legend.title=element_blank())+
    theme_minimal()+theme(legend.title=element_blank())+
    geom_label_repel(aes(label = label), label.size=0.1, size = 2,
                  nudge_x = 2,
                  na.rm = TRUE)
ggsave("../Output/COV/COVscan_3pop/cutoff/PWS_ccr6c_AFchange_ch15_Up.png", width = 6, height=3, dpi=300)

down<-down %>% mutate(label = if_else(year == max(year), as.character(position), NA_character_))
ggplot(down, aes(x=year, y=knownEM))+
    geom_point(size=1.5,color="royalblue", alpha=0.8)+
    geom_path(aes(group=position), size=0.3,color="royalblue" )+ggtitle(paste0("CCRC6 AF changes 1991-2007, Up ",length((unique(maf$position[maf$trend=="down"])))," loci"))+
    ylab("maf")+
    theme(legend.title=element_blank())+
    theme_minimal()+theme(legend.title=element_blank())+
     geom_label_repel(aes(label = label), label.size=0.1, size = 3,
                  nudge_x = 2,
                  na.rm = TRUE)
ggsave("../Output/COV/COVscan_3pop/cutoff/PWS_ccr6c_AFchange_ch15_down.png", width = 6, height=3, dpi=300)

6.1.1 AF changes in all 3 pops

###TB
pops<-c("TB91","TB96","TB06","TB17","PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17")
yr<-c(1991,1996,2006,2017,1991,1996,2007,2017,1996,2006,2017)
maf<-data.frame()
for (i in 1:length(pops)){
    af<-read.table(paste0("../Data/new_vcf/AF/",pops[i],".mafs"),sep="\t", header = T)
    af<-af[af$chromo=="chr15"&af$position>=16050000&af$position<=16100000,]
    af$year<-yr[i]
    af$pop<-sub("\\d\\d","", pops[i])
    maf<-rbind(maf,af)
}
#write.csv(maf,"../Output/COV/COVscan_3pop/AF_maf_chr13_23Mb.csv")


ggplot(maf, aes(x=year, y=knownEM, color=pop))+
    facet_wrap(~factor(position))+
    geom_point(size=1.5)+
    geom_path(linewidth=0.6)+ggtitle("CCRC6 gene (chr15)")+
    ylab("maf")+
    theme(legend.title=element_blank())+
    scale_color_manual(values=cols[c(2,3,1)])
ggsave("../Output/COV/COVscan_3pop/cutoff/ccrc6_AFchanges_allPops.png", width = 8, height=6, dpi=300)

LS0tCnRpdGxlOiAiQ09WIHNjYW4gMyBwb3B1bGF0aW9ucyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICAgIHRvYzogdHJ1ZSAKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgICB0aGVtZTogbHVtZW4KICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKKiBUaGlzIG5vdGVib29rIHN1bW1hcml6ZXMgdGhlIHJlc3VsdHMgZnJvbSB0ZW1wb3JhbCBjb3ZhcmlhbmNlIGFuYWx5c2lzIGZyb20gQ1ZUS1BZLiAgCiogVGhlIGNvdmFyaWFuY2Ugd2luZG93IHNpemUgdXNlZCB3YXMgMTAwayAoYnV0IHRoZSB3aW5kb3cgc2l6ZXMgZGlkIG5vdCBhZmZlY3QgdGhlIHJlc3VsdHMpIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoY293cGxvdCkKbGlicmFyeShzY2FsZXMpCmxpYnJhcnkoZ2d2ZW5uKQpgYGAKCiMgUmVzdWx0cyBmcm9tIENWVEtQWTogZ2Vub21lLXdpZGUgdGVtcG9yYWwgY292YXJpYW5jZXMgb2YgYWxsZWxlIGZyZXF1ZW5jaWVzIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wczwtYygiUFdTIiwiVEIiLCJTUyIpCgpjb3ZzPC1kYXRhLmZyYW1lKCkKZm9yIChwIGluIDE6IGxlbmd0aChwb3BzKSl7CiAgICAjY292YXJpYW5jZSBvdXRwdXQgZmlsZQogICAgY292PC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8zUG9wc19tYWYwNV90ZW1wX2Nvdl9tYXRyaXhfIixwb3BzW3BdLCJfMTAway5jc3YiKSkKICAgIGNvdjwtY292WywtMV0KICAgICAgICAKICAgICNyZXNoYXBlIHRoZSBtYXRyaXgKICAgIG1hdDE8LWNvdlsxOjMsXQogICAgbWF0MjwtY292WzQ6NixdCiAgICAgICAgCiAgICBjb3ZkZjwtZGF0YS5mcmFtZSgpCiAgICBrPTEKICAgIGZvciAoaSBpbiAxOm5yb3cobWF0MSkpewogICAgICAgIGZvciAoaiBpbiAxOm5jb2wobWF0MSkpewogICAgICAgICAgICBjb3ZkZltrLDFdPC1tYXQyW2ksal0KICAgICAgICAgICAgY292ZGZbaywyXTwtbWF0MVtpLGpdCiAgICAgICAgICAgIGs9aysxCiAgICAgICAgfQogICAgfQogICAgY29sbmFtZXMoY292ZGYpPC1jKCJsYWJlbCIsInZhbHVlIikKICAgIGNvdmRmJHZhbHVlPC1hcy5udW1lcmljKGNvdmRmJHZhbHVlKQogICAgY292YXI8LWNvdmRmW2dyZXAoImNvdiIsY292ZGYkbGFiZWwpLF0KICAgICAgICAKICAgICNyZW1vdmUgdGhlIHJlZHVuZGFudCB2YWx1ZXMKICAgIGlmIChwb3BzW3BdIT0iU1MiKSBjb3ZhcjwtY292YXJbIWR1cGxpY2F0ZWQoY292YXJbLCAyXSksXSAKICAgIGlmIChwb3BzW3BdPT0iU1MiKSBjb3ZhcjwtY292YXJbYygxLDIsNCksXQogICAgICAgIAogICAgI2Fzc2lnbiB0aGUgc3RhcnRpbmcgdGltZSBwZXJpb2QgYW5kIGNvdmVyaW5nIHBlcmlvZCB2YWx1ZXMKICAgIGNvdmFyJHllYXI8LWMoMSwyLDIpCiAgICBjb3ZhciRzZXJpZXM8LWMoIjE5OTEiLCIxOTkxIiwiMTk5NiIpCiAgICAgICAgCiAgICAjYXNzaWduIHBvcHVsYXRpb24gbmFtZQogICAgY292YXIkbG9jYXRpb248LXBvcHNbcF0KICAgIAogICAgI2NvbWJpbmUgaW4gdG8gb25lIG1hdHJpeAogICAgY292czwtcmJpbmQoY292cywgY292YXIpCn0KCmNvdnMkdGltZTwtcmVwKGMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpLCAzKQpjb2xuYW1lcyhjb3ZzKVsyXTwtImNvdiIKCiMgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIChjYWxjdWxhdGVkIGZyb20gdGhlICdzdHJhcHMnIHJldHVybmVkIGZyb20gYm9vdHN0cmFwX2NvdjIoKSBjaT0xLjk2KnNkKHN0cmFwcykpCnRpbWU8LWMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpCgpjb3ZzJGNpPC1OQQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpeyAgCiAgICAgaWYgKGkhPTMpewogICAgICAgIGRmPC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8iLHBvcHNbaV0sIl9DSXNfMTAwa3dpbmRvdy5jc3YiKSwgaGVhZGVyPUYpCiAgICAgICAgY292cyRjaVtjb3ZzJGxvY2F0aW9uPT1wb3BzW2ldJnRpbWU9PSdjb3YxMiddPC1kZlsxLDJdCiAgICAgICAgY292cyRjaVtjb3ZzJGxvY2F0aW9uPT1wb3BzW2ldJnRpbWU9PSdjb3YxMyddPC1kZlsxLDNdCiAgICAgICAgY292cyRjaVtjb3ZzJGxvY2F0aW9uPT1wb3BzW2ldJnRpbWU9PSdjb3YyMyddPC1kZlsyLDNdCiAgICB9CiAgICBpZiAocD09MykgewogICAgICAgIGRmPC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8iLHBvcHNbaV0sIl9DSXNfMTAwa3dpbmRvdy5jc3YiKSwgaGVhZGVyPUYpCiAgICAgICAgY292cyRjaVtjb3ZzJGxvY2F0aW9uPT1wb3BzW2ldJnRpbWU9PSdjb3YyMyddPC1kZlsxLDJdIAogICAgfQp9Cgp3cml0ZS5jc3YoY292cywiLi4vT3V0cHV0L0NPVi9HV19jb3ZhcmlhbmNlX0NJcy5jc3YiKQoKeHRleHRzPC1jKCJcdTAzOTQxOTkxLTE5OTZcbiB+IFx1MDM5NDE5OTYtMjAwNiIsICJcbiAgfiBcdTAzOTQyMDA2LTIwMTciKQoKZ2dwbG90KGRhdGE9Y292cywgYWVzKHg9eWVhciwgeT1jb3YsIGNvbG9yPWxvY2F0aW9uLCBzaGFwZT1zZXJpZXMsIGdyb3VwPWludGVyYWN0aW9uKGxvY2F0aW9uLCBzZXJpZXMpKSkrCiAgICAgICAgZ2VvbV9wb2ludChzaXplPTMsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC4xLHByZXNlcnZlID0idG90YWwiKSkrCiAgICAgICAgZ2VvbV9saW5lKGRhdGE9Y292cywgYWVzKHg9eWVhciwgeT1jb3YsY29sb3I9bG9jYXRpb24sIGdyb3VwPWludGVyYWN0aW9uKGxvY2F0aW9uLCBzZXJpZXMpKSwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjEscHJlc2VydmUgPSJ0b3RhbCIpKSsKICAgICAgICB5bGFiKCJDb3ZhcmlhbmNlIikreGxhYignJykrdGhlbWVfY2xhc3NpYygpKwogICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxjb2xvcj0iZ3JheTcwIiwgc2l6ZT0wLjMpKwogICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49Y292LWNpLCB5bWF4PWNvditjaSksIHdpZHRoPS4yLCBzaXplPS4yLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMSxwcmVzZXJ2ZSA9InRvdGFsIikpKwogICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygxNiwxNyksbGFiZWxzPWMoIlx1MDM5NCc5MS0nOTZ+IiwiXHUwMzk0Jzk2LScwNn4iKSkrCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoMSwyKSwgbGFiZWxzPXh0ZXh0cykrCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzW2MoMiwzLDEpXSkreWxpbSgtMC4wMDIzLDAuMDAyKQpnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WLzNQb3BzX0Nvdl9vdmVydGltZV9DSWVzdGltYXRlZC5wbmciKSx3aWR0aCA9IDQuNywgaGVpZ2h0ID0gMywgZHBpPTMwMCkKICAgIApjb3ZzJHRpbWU8LWZhY3Rvcihjb3ZzJHRpbWUsIGxldmVscz1jKCJjb3YxMiIsImNvdjIzIiwiY292MTMiKSkKI3h0ZXh0czwtYygiXHUwMzk0MTk5MS0xOTk2XG4gfiBcdTAzOTQxOTk2LTIwMDYiLCAiXHUwMzk0MTk5Ni0yMDA2XG4gIH4gXHUwMzk0MjAwNi0yMDE3IiwgIlx1MDM5NDE5OTEtMTk5NlxuICB+IFx1MDM5NDIwMDYtMjAxNyIpCnh0ZXh0czwtYygiXHUwMzk0JzkxLSc5NlxuIH4gXHUwMzk0Jzk2LScwNiIsICJcdTAzOTQnOTYtJzA2XG4gIH4gXHUwMzk0JzA2LScxNyIsICJcdTAzOTQnOTEtJzk2XG4gIH4gXHUwMzk0JzA2LScxNyIpCgpnZ3Bsb3QoZGF0YT1jb3ZzLCBhZXMoeD10aW1lLCB5PWNvdiwgY29sb3I9bG9jYXRpb24pKSsKICAgICAgICBnZW9tX3BvaW50KHNpemU9MywgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjEscHJlc2VydmUgPSJ0b3RhbCIpKSsKICAgICAgICAjZ2VvbV9saW5lKGRhdGE9Y292cywgYWVzKHg9eWVhciwgeT1jb3YsY29sb3I9bG9jYXRpb24sIGdyb3VwPWludGVyYWN0aW9uKGxvY2F0aW9uLCBzZXJpZXMpKSwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjEscHJlc2VydmUgPSJ0b3RhbCIpKSsKICAgICAgICB5bGFiKCJDb3ZhcmlhbmNlIikreGxhYignJykrdGhlbWVfY2xhc3NpYygpKwogICAgICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT05KSkrCiAgICAgICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxjb2xvcj0iZ3JheTcwIiwgc2l6ZT0wLjMpKwogICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49Y292LWNpLCB5bWF4PWNvditjaSksIHdpZHRoPS4yLCBzaXplPS4yLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMSxwcmVzZXJ2ZSA9InRvdGFsIikpKwogICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzPXh0ZXh0cykrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYygyLDMsMSldKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSksIGNvbG9yPSJncmF5Iiwgc2l6ZT0wLjIpK3lsaW0oLTAuMDAyMywwLjAwMikKZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi8zUG9wc19Db3ZfQ0lfM3RpbWVwb2ludHMucG5nIiksd2lkdGggPSA0LjU3LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQoKYGBgCiFbXSguLi9PdXRwdXQvQ09WLzNQb3BzX0Nvdl9vdmVydGltZV9DSWVzdGltYXRlZC5wbmcpCgohW10oLi4vT3V0cHV0L0NPVi8zUG9wc19Db3ZfQ0lfM3RpbWVwb2ludHMucG5nKQoKIyBGaW5kIHJlZ2lvbnMgd2l0aCBoaWdoIGNvdmFyaWFuY2VzIGluIGVhY2ggcG9wdWxhdGlvbgoqIEZyb20gVGVtcG9yYWwgQ292YXJpYW5jZSBhbmFseXNpcyAgLW91dHB1dCBjb3ZhcmlhbmNlcyBmb3IgZWFjaCB0aW1lIHBlcmlvZAoKIyMgUGxvdCB0aGUgY292YXJpYW5jZXMgYWNyb3NzIHRoZSBnZW5vbWUgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiNGaW5kIHRoZSByZWdpb25zIHdpdGggYSBoaWdoIHRlbXBvcmFsIGNvdmFyaWFuY2UgCnBvcHM8LWMoIlBXUyIsIlRCIiwiU1MiKQp3aW5zaXplPC0iMTAwayIKZXZlbnM8LXBhc3RlMCgiY2hyIixzZXEoMiwyNiwgYnk9MikpCmNvdi5saXN0PC1saXN0KCkKY292c19hbGw8LWxpc3QoKQprPTEKZm9yIChwIGluIDE6IGxlbmd0aChwb3BzKSl7CiAgICBwb3A8LXBvcHNbcF0KICAgIGl2PC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8zcG9wc19pbnRlcnZhbHNfIix3aW5zaXplLCJ3aW5kb3cuY3N2IiksIHJvdy5uYW1lcyA9IDEpCiAgICBpZiAocD09MykgewogICAgICAgIGNvdjIzPC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8iLHBvcCwiX2NvdjIzXzIwMTctMjAwNl8yMDA2LTE5OTZfM1BvcHNfIix3aW5zaXplLCJ3aW5kb3cuY3N2IiksIGhlYWRlciA9IEYpCiAgICAgICAgY292czwtY2JpbmQoaXYsIGNvdjIzKQogICAgICAgIGNvbG5hbWVzKGNvdnMpWzRdPC1jKCJjb3YyMyIpCiAgICAgICAgY292cyRpbmRleD0xOm5yb3coY292cykKICAgICAgICBjb3ZzJGNvbG9yPC0iY29sMSIKICAgICAgICBjb3ZzJGNvbG9yW2NvdnMkY2hyb20gJWluJSBldmVuc108LSJjb2wyIgoKICAgICAgICBjb3ZzW3NhcHBseShjb3ZzLCBpcy5pbmZpbml0ZSldIDwtIE5BCiAgICAgICAgY292c1tzYXBwbHkoY292cywgaXMubmFuKV0gPC0gTkEKICAgICAgICAKICAgICAgICBjb3YubGlzdFtba11dPC1jb3ZzCiAgICAgICAgbmFtZXMoY292Lmxpc3QpW2tdPC1wYXN0ZTAocG9wLCJfIix3aW5zaXplKSAgICAKICAgICAgICBrPWsrMQogICAgICAgICAgICAKICAgICAgICB5PC1taW4oY292cyRjb3YyMywgbmEucm09VCkKICAgICAgICB5bWluPC1pZmVsc2UgKHk8PS0wLjEsLTAuMSwgeSkgCiAgICAgICAgeW1heDwtbWF4KGNvdnMkY292MjMsIG5hLnJtPVQpCiAgICAgICAgZ2dwbG90KGNvdnMsIGFlcyh4PWluZGV4LCB5PWNvdjIzLCBjb2xvcj1jb2xvcikpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MSwgYWxwaGE9MC41KSsKICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpKwogICAgICAgICAgICB5bGltKHltaW4seW1heCkrCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JheTcwIiwic3RlZWxibHVlIiksIGd1aWRlPSJub25lIikrCiAgICAgICAgICAgIHlsYWIoIkNvdmFyaWFuY2UiKSt4bGFiKCdDaHJvbW9zb21lJykrCiAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgICAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wLCIgIiwgd2luc2l6ZSwiIHdpbmRvdyIpKQogICAgICAgICNnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WLzNQb3BzLiIscG9wLCJfdGVtcENvdnNfYWNyb3NzR2Vub21lXyIsd2luc2l6ZVtpXSwgIldpbmRvdy5wbmciKSwgd2lkdGggPSA4LCBoZWlnaHQgPSAyLjcsIGRwaT0zMDApIAogICAgICAgIH0KICAgIGVsc2UgewogICAgICAgIGNvdjEyPC1yZWFkLmNzdihwYXN0ZTAoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC8iLHBvcCwiX2NvdjEyXzE5OTYtMTk5MV8yMDA2LTE5OTZfM1BvcHNfIix3aW5zaXplLCJ3aW5kb3cuY3N2IiksIGhlYWRlciA9IEYpCiAgICAgICAgY292MjM8LXJlYWQuY3N2KHBhc3RlMCgifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvTUQ3MDAwLyIscG9wLCJfY292MjNfMjAxNy0yMDA2XzIwMDYtMTk5Nl8zUG9wc18iLHdpbnNpemUsIndpbmRvdy5jc3YiKSwgaGVhZGVyID0gRikKICAgICAgICBjb3YxMzwtcmVhZC5jc3YocGFzdGUwKCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvIixwb3AsIl9jb3YxM18yMDE3LTIwMDZfMTk5Ni0xOTkxXzNQb3BzXyIsd2luc2l6ZSwid2luZG93LmNzdiIpLCBoZWFkZXIgPSBGKQogICAgICAgIGNvdnM8LWNiaW5kKGl2LCBjb3YxMiwgY292MjMsY292MTMpCiAgICAgICAgY29sbmFtZXMoY292cylbNDo2XTwtYygiY292MTIiLCJjb3YyMyIsImNvdjEzIikKICAgICAgICBjb3ZzJGluZGV4PTE6bnJvdyhjb3ZzKQogICAgCiAgICAgICAgY292cyRjb2xvcjwtImNvbDEiCiAgICAgICAgY292cyRjb2xvcltjb3ZzJGNocm9tICVpbiUgZXZlbnNdPC0iY29sMiIKICAgIAogICAgICAgIGNvdnNbc2FwcGx5KGNvdnMsIGlzLmluZmluaXRlKV0gPC0gTkEKICAgICAgICBjb3ZzW3NhcHBseShjb3ZzLCBpcy5uYW4pXSA8LSBOQQogICAgICAgIAogICAgICAgIGNvdi5saXN0W1trXV08LWNvdnMKICAgICAgICBuYW1lcyhjb3YubGlzdClba108LXBhc3RlMChwb3AsIl8iLHdpbnNpemUpICAgIAogICAgICAgIGs9aysxCiAgICAgICAgY292c208LW1lbHQoY292c1ssYygiaW5kZXgiLCJjb2xvciIsImNvdjEyIiwiY292MjMiLCJjb3YxMyIpXSwgaWQudmFycyA9IGMoImluZGV4IiwgImNvbG9yIikpCiAgICAgICAgeW1heDwtbWF4KGNvdnNtJHZhbHVlLCBuYS5ybT1UKQogICAgICAgIHk8LW1pbihjb3ZzbSR2YWx1ZSwgbmEucm09VCkKICAgICAgICB5bWluPC1pZmVsc2UgKHk8PS0wLjEsLTAuMSwgeSkgCiAgICAgICAgZ2dwbG90KGNvdnNtLCBhZXMoeD1pbmRleCwgeT12YWx1ZSwgY29sb3I9Y29sb3IpKSsKICAgICAgICAgICAgZmFjZXRfd3JhcCh+dmFyaWFibGUsIG5yb3c9MykrCiAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0xLCBhbHBoYT0wLjUpKwogICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgICAgIHlsaW0oeW1pbix5bWF4KSsKICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmF5NzAiLCJzdGVlbGJsdWUiKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICAgICAgeWxhYigiQ292YXJpYW5jZSIpK3hsYWIoJ0Nocm9tb3NvbWUnKSsKICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMChwb3AsIiAiLCB3aW5zaXplLCIgd2luZG93IikpCiAgICAgICAgI2dnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvM1BvcHMuIixwb3AsIl90ZW1wQ292c19hY3Jvc3NHZW5vbWVfIix3aW5zaXplLCAiV2luZG93LnBuZyIpLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgsIGRwaT0zMDApICAgIAogICAgfQp9CmBgYAoKIVtdKC4uL091dHB1dC9DT1YvM1BvcHMuUFdTX3RlbXBDb3ZzX2Fjcm9zc0dlbm9tZV8xMDBrV2luZG93LnBuZyl7d2lkdGg9NjUlfQoKIVtdKC4uL091dHB1dC9DT1YvM1BvcHMuVEJfdGVtcENvdnNfYWNyb3NzR2Vub21lXzEwMGtXaW5kb3cucG5nKXt3aWR0aD02NSV9ICAgCgohW10oLi4vT3V0cHV0L0NPVi8zUG9wcy5TU190ZW1wQ292c19hY3Jvc3NHZW5vbWVfMTAwa1dpbmRvdy5wbmcpe3dpZHRoPTY1JX0gIAoKCiMgRmluZCB0aGUgY292YXJpYW5jZSBsb3dlciBjdXQgb2ZmIHZhbHVlcyAgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpjdjwtYygiY292MTIiLCJjb3YxMyIsImNvdjIzIikKY3ZyYW5nZTwtZGF0YS5mcmFtZShwb3A9YyhwYXN0ZTAocG9wc1sxOjJdLCJfIiwgY3ZbMV0pLHBhc3RlMChwb3BzWzE6Ml0sIl8iLCBjdlsyXSkscGFzdGUwKHBvcHMsIl8iLCBjdlszXSkpKQprPTEKZm9yIChpIGluIDE6bGVuZ3RoKGN2KSl7CiAgICBpZiAoaT09MXxpPT0yKXsKICAgICAgICBpZiAoaT09MSkgaz0xCiAgICAgICAgaWYgKGk9PTIpIGs9MwogICAgICAgICNQV1MKICAgICAgICBkZjE8LWNvdi5saXN0W1twYXN0ZTAoIlBXU18xMDBrIildXQogICAgICAgIGRmMTwtZGYxW29yZGVyKGRmMVssY3ZbaV1dLCBkZWNyZWFzaW5nPVQpLF0KICAgICAgICBuPC1jZWlsaW5nKG5yb3coZGYxKSowLjAxKSAjdG9wMSUgcmVnaW9uCiAgICAgICAgZGYxJHRvcDE8LSJOIgogICAgICAgIGRmMSR0b3AxWzE6bl08LSJQV1MiCiAgICAgICAgcmc8LXJhbmdlKGRmMVtkZjEkdG9wMT09IlBXUyIsY3ZbaV1dLCBuYS5ybT1UKQogICAgICAgIGN2cmFuZ2VbaywiMTAwayJdPC1wYXN0ZTAocmdbMV0sIi0iLHJnWzJdKQogICAgICAgICAgCiAgICAgICAgI3RiCiAgICAgICAgZGYyPC1jb3YubGlzdFtbIlRCXzEwMGsiXV0KICAgICAgICBkZjI8LWRmMltvcmRlcihkZjJbLGN2W2ldXSwgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgZGYyJHRvcDE8LSJOIgogICAgICAgIGRmMiR0b3AxWzE6bl08LSJUQiIKICAgICAgICByZzI8LXJhbmdlKGRmMltkZjIkdG9wMT09IlRCIiwgY3ZbaV1dLCBuYS5ybT1UKQogICAgICAgIGN2cmFuZ2VbKGsrMSksIjEwMGsiXTwtcGFzdGUwKHJnMlsxXSwiLSIscmcyWzJdKQogICAgfQogICAKICAgIGlmIChpPT0zKXsKICAgICAgICBrPTUKICAgICAgICAjcHdzCiAgICAgICAgZGYxPC1jb3YubGlzdFtbIlBXU18xMDBrIl1dCiAgICAgICAgZGYxPC1kZjFbLGMoImNocm9tIiwic3RhcnQiLCJlbmQiLCJjb3YyMyIpXQogICAgICAgIGRmMTwtZGYxW29yZGVyKGRmMSRjb3YyMywgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgbjwtY2VpbGluZyhucm93KGRmMSkqMC4wMSkgI3RvcDElIHJlZ2lvbgogICAgICAgIGRmMSR0b3AxPC0iTiIKICAgICAgICBkZjEkdG9wMVsxOm5dPC0iUFdTIgogICAgICAgIAogICAgICAgIHJnPC1yYW5nZShkZjFbZGYxJHRvcDE9PSJQV1MiLGN2W2ldXSwgbmEucm09VCkKICAgICAgICBjdnJhbmdlW2ssIjEwMGsiXTwtcGFzdGUwKHJnWzFdLCItIixyZ1syXSkKICAgICAgICAgICAKICAgICAgICAjdGIKICAgICAgICBkZjI8LWNvdi5saXN0W1siVEJfMTAwayJdXQogICAgICAgIGRmMjwtZGYyWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIiwiY292MjMiKV0KICAgICAgICBkZjI8LWRmMltvcmRlcihkZjIkY292MjMsIGRlY3JlYXNpbmc9VCksXQogICAgICAgIGRmMiR0b3AxPC0iTiIKICAgICAgICBkZjIkdG9wMVsxOm5dPC0iVEIiCiAgICAgICAgcmcyPC1yYW5nZShkZjJbZGYyJHRvcDE9PSJUQiIsIGN2W2ldXSwgbmEucm09VCkKICAgICAgICBjdnJhbmdlWyhrKzEpLCIxMDBrIl08LXBhc3RlMChyZzJbMV0sIi0iLHJnMlsyXSkKICAgIAogICAgICAgICNzcwogICAgICAgIGRmMzwtY292Lmxpc3RbWyJTU18xMDBrIl1dCiAgICAgICAgZGYzPC1kZjNbLGMoImNocm9tIiwic3RhcnQiLCJlbmQiLCJjb3YyMyIpXQogICAgICAgIGRmMzwtZGYzW29yZGVyKGRmMyRjb3YyMywgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgZGYzJHRvcDE8LSJOIgogICAgICAgIGRmMyR0b3AxWzE6bl08LSJTUyIKICAgICAgICByZzM8LXJhbmdlKGRmM1tkZjMkdG9wMT09IlNTIiwgY3ZbaV1dLCBuYS5ybT1UKQogICAgICAgIGN2cmFuZ2VbKGsrMiksIjEwMGsiXTwtcGFzdGUwKHJnM1sxXSwiLSIscmczWzJdKQogICAgICAgIH0KICAgIH0KfQoKY3ZzPC1tZWx0KGN2cmFuZ2UsIGlkLnZhcnMgPSAicG9wIikKY3ZzPC1jdnMgJT4lCiAgc2VwYXJhdGUodmFsdWUsIGMoImxvdyIsICJoaWdoIiksICItIikKY3ZzJGxvdzwtYXMubnVtZXJpYyhjdnMkbG93KQpjdnMkaGlnaDwtYXMubnVtZXJpYyhjdnMkaGlnaCkKY3ZzPC1jdnMlPiUKICBzZXBhcmF0ZShwb3AsIGMoInBvcCIsICJjb3YiKSwgIl8iKQoKZ2dwbG90KGN2cywgYWVzKHg9Y292LCB5PWhpZ2gsIGZpbGw9cG9wKSkrCiAgICBnZW9tX2Nyb3NzYmFyKGFlcyh5bWluPWxvdywgeW1heD1oaWdoKSwgd2lkdGg9MC41LCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpKSsKICAgIHlsYWIoIlJhbmdlIG9mIGNvdmFyaWFuY2VzIikrCiAgICB0aGVtZV9saWdodCgpK3hsYWIoIiIpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PWMoMS41LDIuNSksIGNvbG9yPSJncmF5IikrCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLCBsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsKICAgIGdndGl0bGUoIlRvcDElIENvdiBSYW5nZSIpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvVGVtcENvdl9SYW5nZV9jb21wYXJpc29uXzEwMGsucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQoKZ2dwbG90KGN2cywgYWVzKHg9Y292LCB5PWxvdywgY29sb3I9cG9wKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICB5bGFiKCJMb3dlciBsaW1pdCBvZiB0b3AgMSUgY292YXJpYW5jZSIpKwogICAgdGhlbWVfbGlnaHQoKSt4bGFiKCIiKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdD1jKDEuNSwyLjUpLCBjb2xvcj0iZ3JheSIpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9UZW1wQ292X1JhbmdlX2xvd0xpbWl0X2NvbXBhcmlzb25fMTAway5wbmciLCB3aWR0aCA9IDUsIGhlaWdodCA9IDMsIGRwaT0zMDApCgpgYGAKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9UZW1wQ292X1JhbmdlX2NvbXBhcmlzb25fMTAway5wbmcpCgoKIVtdKC4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL1RlbXBDb3ZfUmFuZ2VfbG93TGltaXRfY29tcGFyaXNvbl8xMDBrLnBuZykKCiMjIFVzZSB0aGUgbG93ZXN0IGNvdmFyaWFuY2UgdmFsdWVzIGZvciBlYWNoIHBlcmlvZCB0byBkZWZpbnRlIG91dGxpZXIgcmVnaW9ucyAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cgpsb3dzPC1hZ2dyZWdhdGUoY3ZzJGxvdywgYnk9bGlzdChjdnMkY292KSwgbWluKQpuYW1lcyhsb3dzKTwtYygiY292IiwibG93IikKI2xvdyBjdXRvZmYgZm9yIGVhY2ggdGltZSBwZXJpb2QgKDEwMGstd2luZG93KQojICAgICBjb3YgICAgICAgIGxvdwojMSBjb3YxMiAwLjAyODc0ODQxCiMyIGNvdjEzIDAuMDMxMDI3MTIKIzMgY292MjMgMC4wMzI0NjUyNAoKCiMgT3V0bGllcnMgYmFzZWQgb24gdGhlIG5ldyBsb3cgY3V0LW9mZiB2YWx1ZXMgMTAwayB3aW5kb3cuIApjb3YxMjwtZGF0YS5mcmFtZSgpCmNvdjIzPC1kYXRhLmZyYW1lKCkKY292MTM8LWRhdGEuZnJhbWUoKQoKZm9yIChpIGluIDE6bGVuZ3RoKGNvdi5saXN0KSl7CiAjUFdTIGFuZCBUQgogIGlmIChpPT0xfGk9PTIpewogICAgY292czwtY292Lmxpc3RbW2ldXQogICAgcG9wPC1nc3ViKCJfLisiLCcnLCBuYW1lcyhjb3YubGlzdClbaV0pCiAgCiAgICAjb3V0bGllciBjdXRvZmYgdmFsdWUKICAgIHg8LWxvd3MkbG93W2xvd3MkY292PT0iY292MTIiXQogICAgY292czEyX3RvcDwtc3Vic2V0KGNvdnMsIGNvdjEyPj14KQogICAgY292czEyX3RvcDwtY292czEyX3RvcFtvcmRlcihjb3ZzMTJfdG9wJGNocm9tLCBjb3ZzMTJfdG9wJHN0YXJ0KSxdCiAgICBjb3ZzMTJfdG9wJHBvcDwtcG9wCiAgICBjb3YxMjwtcmJpbmQoY292MTIsIGNvdnMxMl90b3ApCiAgICAKICAgIGNvdnM8LWNvdnNbb3JkZXIoY292cyRjb3YxMywgZGVjcmVhc2luZz1UKSxdCiAgICB4PC1sb3dzJGxvd1tsb3dzJGNvdj09ImNvdjEzIl0KICAgIGNvdnMxM190b3A8LXN1YnNldChjb3ZzLCBjb3YxMz49eCkKICAgIGNvdnMxM190b3A8LWNvdnMxM190b3Bbb3JkZXIoY292czEzX3RvcCRjaHJvbSwgY292czEzX3RvcCRzdGFydCksXQogICAgY292czEzX3RvcCRwb3A8LXBvcAogICAgY292MTM8LXJiaW5kKGNvdjEzLCBjb3ZzMTNfdG9wKQogICAgCiAgICBjb3ZzPC1jb3ZzW29yZGVyKGNvdnMkY292MjMsIGRlY3JlYXNpbmc9VCksXQogICAgeDwtbG93cyRsb3dbbG93cyRjb3Y9PSJjb3YyMyJdCiAgICBjb3ZzMjNfdG9wPC1zdWJzZXQoY292c1ssYygiY2hyb20iLCJzdGFydCIsImVuZCIsImNvdjIzIiwiaW5kZXgiLCJjb2xvciIpXSwgY292MjM+PXgpCiAgICBjb3ZzMjNfdG9wPC1jb3ZzMjNfdG9wW29yZGVyKGNvdnMyM190b3AkY2hyb20sIGNvdnMyM190b3Akc3RhcnQpLF0KICAgIGNvdnMyM190b3AkcG9wPC1wb3AKICAgIGNvdjIzPC1yYmluZChjb3YyMywgY292czIzX3RvcCkKIH0KIGlmIChncmVwbCgiU1MiLG5hbWVzKGNvdi5saXN0KVtpXSkpewogICAgY292czwtY292Lmxpc3RbW2ldXQogICAgCiAgICBwb3A8LWdzdWIoIl8uKyIsJycsIG5hbWVzKGNvdi5saXN0KVtpXSkKICAgIHdpbjwtZ3N1YihwYXN0ZTAocG9wLCJfIiksICcnLCBuYW1lcyhjb3YubGlzdClbaV0pCiAgICAKICAgIGNvdnM8LWNvdnNbb3JkZXIoY292cyRjb3YyMywgZGVjcmVhc2luZz1UKSxdCiAgICB4PC1sb3dzJGxvd1tsb3dzJGNvdj09ImNvdjIzIl0KICAgIGNvdnMyM190b3A8LXN1YnNldChjb3ZzLCBjb3YyMz49eCkKICAgIGNvdnMyM190b3A8LWNvdnMyM190b3Bbb3JkZXIoY292czIzX3RvcCRjaHJvbSwgY292czIzX3RvcCRzdGFydCksXQogICAgY292czIzX3RvcCRwb3A8LXBvcAogICAgY292MjM8LXJiaW5kKGNvdjIzLCBjb3ZzMjNfdG9wKQogICAgfQp9Cgp3cml0ZS5jc3YoY292MTIsICIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvM3BvcHNfdG9wMXBlcmNlbnRfb3V0bGllcl9jdXRvZmYuY292MTIuY3N2Iixyb3cubmFtZXMgPSBGKQp3cml0ZS5jc3YoY292MjMsICIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvM3BvcHNfdG9wMXBlcmNlbnRfb3V0bGllcl9jdXRvZmYuY292MjMuY3N2Iixyb3cubmFtZXMgPSBGKQp3cml0ZS5jc3YoY292MTMsICIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvM3BvcHNfdG9wMXBlcmNlbnRfb3V0bGllcl9jdXRvZmYuY292MTMuY3N2Iixyb3cubmFtZXMgPSBGKQpgYGAKCgojIyMgU3RyaWNrdGVyIGNvdmFyaWFuY2UgY3V0b2ZmIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojCmNvdjEyPC1kYXRhLmZyYW1lKCkKY292MjM8LWRhdGEuZnJhbWUoKQpjb3YxMzwtZGF0YS5mcmFtZSgpCm5hbWVzKGNvdi5saXN0KQpmb3IgKGkgaW4gMTpsZW5ndGgoY292Lmxpc3QpKXsKICNQV1MgYW5kIFRCCiAgaWYgKGk9PTF8aT09Mil7CiAgICBjb3ZzPC1jb3YubGlzdFtbaV1dCiAgICBwb3A8LWdzdWIoIl8uKyIsJycsIG5hbWVzKGNvdi5saXN0KVtpXSkKICAgIAogICAgcGxvdChjb3ZzJGNvdjEyKQogIAogICAgI291dGxpZXIgY3V0b2ZmIHZhbHVlCiAgICB4PC1sb3dzJGxvd1tsb3dzJGNvdj09ImNvdjEyIl0KICAgIGNvdnMxMl90b3A8LXN1YnNldChjb3ZzLCBjb3YxMj49eCkKICAgICMgY292IGN1dG9mZiBhdCAwLjAzNQogICAgYzEyPC1jb3ZzMTJfdG9wW2NvdnMxMl90b3AkY292MTIgPjAuMDM1LF0gCiAgICAKICAgICNjcmVhdGUgYSBiZWQgZmlsZSBmb3IgdGhlIHJlaW9uCiAgICBkZjwtYzEyWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIildCiAgICAjYWRkIDEwMGsKICAgIGRmJHN0YXJ0PC1kZiRzdGFydC0xMDAwMDAKICAgIGRmJGVuZDwtZGYkZW5kKzEwMDAwMAogICAgZGZwPC1kZltkZiRwb3A9PSJQV1MiLDE6M10KICAgIGNvbG5hbWVzKGRmcCk8LWMoJ3RyYWNrIHR5cGU9YmVkR3JhcGgnLCAnMScsJzEnKQogICAgd3JpdGUudGFibGUoZGZwLCBwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9QV1Nfb3V0bGllcnNfIixjdltpXSwiX25ldy5iZWQiKSxxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IFQsc2VwID0gIlx0IikKICAKICAgIAogICAgY292czEyX3RvcDwtY292czEyX3RvcFtvcmRlcihjb3ZzMTJfdG9wJGNocm9tLCBjb3ZzMTJfdG9wJHN0YXJ0KSxdCiAgICBjb3ZzMTJfdG9wJHBvcDwtcG9wCiAgICBjb3YxMjwtcmJpbmQoY292MTIsIGNvdnMxMl90b3ApCiAgICAKICAgIGNvdnM8LWNvdnNbb3JkZXIoY292cyRjb3YxMywgZGVjcmVhc2luZz1UKSxdCiAgICB4PC1sb3dzJGxvd1tsb3dzJGNvdj09ImNvdjEzIl0KICAgIGNvdnMxM190b3A8LXN1YnNldChjb3ZzLCBjb3YxMz49eCkKICAgIGNvdnMxM190b3A8LWNvdnMxM190b3Bbb3JkZXIoY292czEzX3RvcCRjaHJvbSwgY292czEzX3RvcCRzdGFydCksXQogICAgY292czEzX3RvcCRwb3A8LXBvcAogICAgY292MTM8LXJiaW5kKGNvdjEzLCBjb3ZzMTNfdG9wKQogICAgCiAgICBjb3ZzPC1jb3ZzW29yZGVyKGNvdnMkY292MjMsIGRlY3JlYXNpbmc9VCksXQogICAgeDwtbG93cyRsb3dbbG93cyRjb3Y9PSJjb3YyMyJdCiAgICBjb3ZzMjNfdG9wPC1zdWJzZXQoY292c1ssYygiY2hyb20iLCJzdGFydCIsImVuZCIsImNvdjIzIiwiaW5kZXgiLCJjb2xvciIpXSwgY292MjM+PXgpCiAgICBjb3ZzMjNfdG9wPC1jb3ZzMjNfdG9wW29yZGVyKGNvdnMyM190b3AkY2hyb20sIGNvdnMyM190b3Akc3RhcnQpLF0KICAgIGNvdnMyM190b3AkcG9wPC1wb3AKICAgIGNvdjIzPC1yYmluZChjb3YyMywgY292czIzX3RvcCkKIH0KIGlmIChncmVwbCgiU1MiLG5hbWVzKGNvdi5saXN0KVtpXSkpewogICAgY292czwtY292Lmxpc3RbW2ldXQogICAgCiAgICBwb3A8LWdzdWIoIl8uKyIsJycsIG5hbWVzKGNvdi5saXN0KVtpXSkKICAgIHdpbjwtZ3N1YihwYXN0ZTAocG9wLCJfIiksICcnLCBuYW1lcyhjb3YubGlzdClbaV0pCiAgICAKICAgIGNvdnM8LWNvdnNbb3JkZXIoY292cyRjb3YyMywgZGVjcmVhc2luZz1UKSxdCiAgICB4PC1sb3dzJGxvd1tsb3dzJGNvdj09ImNvdjIzIl0KICAgIGNvdnMyM190b3A8LXN1YnNldChjb3ZzLCBjb3YyMz49eCkKICAgIGNvdnMyM190b3A8LWNvdnMyM190b3Bbb3JkZXIoY292czIzX3RvcCRjaHJvbSwgY292czIzX3RvcCRzdGFydCksXQogICAgY292czIzX3RvcCRwb3A8LXBvcAogICAgY292MjM8LXJiaW5kKGNvdjIzLCBjb3ZzMjNfdG9wKQogICAgfQp9CmBgYAoKCiMjIENyZWF0ZSBwbG90cyB3aXRoIGRpZmZlcmVudCBjb2xvcnMgZm9yIG91dGxpZXJzCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojZm9yIENPVjEyIGFuZCBDT1YxMyBmb3IgVEIgYW5kIFBXUyAoMTAwSykKY3Y8LWMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpCgpmb3IgKGkgaW4gMTpsZW5ndGgoY3YpKXsKICAgIGlmIChpPT0xfGk9PTIpewogICAgICAgICNjdXRvZmYgdmFsdWUKICAgICAgICB4PC1sb3dzJGxvd1tsb3dzJGNvdj09Y3ZbaV1dCiAgICAgICAgI1BXUwogICAgICAgIGRmMTwtY292Lmxpc3RbWyJQV1NfMTAwayJdXQogICAgICAgIGRmMTwtZGYxW29yZGVyKGRmMVssY3ZbaV1dLCBkZWNyZWFzaW5nPVQpLF0KICAgICAgICBkZjEkdG9wMTwtIk4iCiAgICAgICAgZGYxJHRvcDFbZGYxWyxjdltpXV0+PXhdPC0iUFdTIgogICAgICAgIAogICAgICAgICN0YgogICAgICAgIGRmMjwtY292Lmxpc3RbWyJUQl8xMDBrIl1dCiAgICAgICAgZGYyPC1kZjJbb3JkZXIoZGYyWyxjdltpXV0sIGRlY3JlYXNpbmc9VCksXQogICAgICAgIGRmMiR0b3AxPC0iTiIKICAgICAgICBkZjIkdG9wMVtkZjJbLGN2W2ldXT49eF08LSJUQiIKICAgICAgICAKICAgICAgICAjQ29tYmluZSBQV1MgYW5kIFRCIHRhYmxlcwogICAgICAgIGNvPC1yYmluZChkZjEsIGRmMikKICAgICAgICBjbyRjaHJvbTwtZmFjdG9yKGNvJGNocm9tLCBsZXZlbHM9cGFzdGUwKCJjaHIiLCAxOjI2KSkKICAgICAgICBjbyR0b3AxPC1mYWN0b3IoY28kdG9wMSwgbGV2ZWxzPWMoIlBXUyIsIlRCIiwiTiIpKQogICAgICAgIGNvbG5hbWVzKGNvKVt3aGljaChjb2xuYW1lcyhjbyk9PWN2W2ldKV08LSJjb3YiCiAgICAKICAgICAgICB5bWF4PC1tYXgoY28kY292LCBuYS5ybT1UKQogICAgICAgICNQbG90IGVhY2ggZ2Vub21lIHNlcGFyYXRlbHkKICAgICAgICBnZ3Bsb3QoY28sIGFlcyh4PXN0YXJ0LzEwMDAwMDAsIHk9Y292LCBjb2xvcj10b3AxKSkrCiAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpKwogICAgICAgICAgICBmYWNldF93cmFwKH5jaHJvbSwgbmNvbD00KSsKICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpK3lsaW0oLTAuMSx5bWF4KSsKICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKHBhc3RlMChjb2xzWzJdLCJCMyIpLHBhc3RlMChjb2xzWzFdLCJCMyIpICwiI0MwQzBDMDgwIiksIGxhYmVscz1jKCJQV1MiLCAiVEIiLCAiIikpKwogICAgICAgICAgICB5bGFiKCJDb3ZhcmlhbmNlIikreGxhYignUG9zdGlvbiAoTWIpJykrCiAgICAgICAgICAgIGdndGl0bGUoY3ZbaV0pKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpKwogICAgICAgICAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvcj1jKGNvbHNbMl0sY29sc1sxXSwid2hpdGUiKSxzaXplPTIpLCB0aXRsZT1lbGVtZW50X3RleHQoIlRvcCAxJSIpKSkKICAgCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLzNQb3BzLiIsY3ZbaV0sIl9wZXJDaHJvbV8xMDBrX1dpbmRvd19PdXRsaWVycy5wbmciKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOCwgZHBpPTMwMCkKICAgICAgICAKICAgICAgICAjV2hvbGUgZ2Vub21lIGluIDEgcGxvdCAKICAgICAgICAjYXNzaWduIGNvbG9ycwogICAgICAgIGNvJHRvcDE8LWFwcGx5KGNvLCAxLCBmdW5jdGlvbih4KSB7aWZlbHNlICh4Wyd0b3AxJ109PSJOIiwgeFsnY29sb3InXSwgeFsndG9wMSddKX0gKQogICAgICAgIGNvJHRvcDE8LWZhY3RvcihjbyR0b3AxLCBsZXZlbHM9YygiUFdTIiwiVEIiLCJjb2wxIiwiY29sMiIpKQogICAgICAgIAogICAgICAgICNjb3VudCB0aGUgbnVtYmVyIG9mIHNpdGVzIHBlciBjaHJvbW9zb21lcwogICAgICAgIHBvc3M8LWRhdGEuZnJhbWUoY2hyPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgICAgICBrPTEKICAgICAgICBmb3IgKGogaW4gMToyNil7CiAgICAgICAgICAgIGRmPC1kZjFbZGYxJGNocj09cGFzdGUwKCJjaHIiLGopLF0KICAgICAgICAgICAgcG9zcyRzdGFydFtqXTwtawogICAgICAgICAgICBwb3NzJGVuZFtqXTwtaytucm93KGRmKS0xCiAgICAgICAgICAgIGs9aytucm93KGRmKQogICAgICAgIH0KICAgICAgICBwb3NzJHg8LXBvc3Mkc3RhcnQrKHBvc3MkZW5kLXBvc3Mkc3RhcnQpLzIKICAgICAgICB5bWF4PC1tYXgoY28kY292LCBuYS5ybT1UKQogICAgICAgIGdncGxvdChjbywgYWVzKHg9aW5kZXgsIHk9Y292LCBjb2xvcj10b3AxKSkrCiAgICAgICAgICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpKwogICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkreWxpbSgtMC4xLHltYXgpKwogICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMocGFzdGUwKGNvbHNbMl0sIkIzIikscGFzdGUwKGNvbHNbMV0sIkIzIiksIiNBOEJCQ0Q2NiIsIiNENkQ2RDY2NiIpLCBsYWJlbHM9YygiUFdTIiwgIlRCIiwgIiIsIiIpKSsKICAgICAgICAgICAgeWxhYigiQ292YXJpYW5jZSIpKwogICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMCgiIDEwMGsgd2luZG93ICIsY3ZbaV0pKSsKICAgICAgICAgICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QoY29sb3I9Yyhjb2xzWzJdLCBjb2xzWzFdLCJ3aGl0ZSIsIndoaXRlIiksIHNpemU9MiksIHRpdGxlPWVsZW1lbnRfdGV4dCgiT3V0bGllciBSZWdpb24iLCBzaXplPTEwKSkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZT0iQ2hyb21vc29tZSIsIGJyZWFrcz1wb3NzJHgsIGxhYmVscz0xOjI2KQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8zUG9wcy4iLGN2W2ldLCJfMTAwa19XaW5kb3dfT3V0bGllcnMucG5nIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDMuNSwgZHBpPTMwMCkKICAgIH0KICAgCiAgICBpZiAoaT09Myl7CiAgICAgICAjY3V0b2ZmIHZhbHVlCiAgICAgICAgeDwtbG93cyRsb3dbbG93cyRjb3Y9PWN2W2ldXQogICAgICAgICNQV1MKICAgICAgICBkZjE8LWNvdi5saXN0W1siUFdTXzEwMGsiXV0KICAgICAgICBkZjE8LWRmMVssYygiY2hyb20iLCJzdGFydCIsImVuZCIsImNvdjIzIiwiaW5kZXgiLCJjb2xvciIpXQogICAgICAgIGRmMTwtZGYxW29yZGVyKGRmMSRjb3YyMywgZGVjcmVhc2luZz1UKSxdCiAgICAgICAgZGYxJHRvcDE8LSJOIgogICAgICAgIGRmMSR0b3AxW2RmMVssY3ZbaV1dPj14XTwtIlBXUyIKICAgICAgICAKICAgICAgICAjdGIKICAgICAgICBkZjI8LWNvdi5saXN0W1siVEJfMTAwayJdXQogICAgICAgIGRmMjwtZGYyWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIiwiY292MjMiLCJpbmRleCIsImNvbG9yIildCiAgICAgICAgZGYyPC1kZjJbb3JkZXIoZGYyJGNvdjIzLCBkZWNyZWFzaW5nPVQpLF0KICAgICAgICBkZjIkdG9wMTwtIk4iCiAgICAgICAgZGYyJHRvcDFbZGYyWyxjdltpXV0+PXhdPC0iVEIiCiAgICAKICAgICAgICAjc3MKICAgICAgICBkZjM8LWNvdi5saXN0W1siU1NfMTAwayJdXQogICAgICAgIGRmMzwtZGYzWyxjKCJjaHJvbSIsInN0YXJ0IiwiZW5kIiwiY292MjMiLCJpbmRleCIsImNvbG9yIildCiAgICAgICAgZGYzPC1kZjNbb3JkZXIoZGYzJGNvdjIzLCBkZWNyZWFzaW5nPVQpLF0KICAgICAgICBkZjMkdG9wMTwtIk4iCiAgICAgICAgZGYzJHRvcDFbZGYzWyxjdltpXV0+PXhdPC0iU1MiCgogICAgICAgIGNvPC1yYmluZChkZjEsZGYyLGRmMykKCiAgICAgICAgY28kY2hyb208LWZhY3RvcihjbyRjaHJvbSwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwgMToyNikpCiAgICAgICAgY28kdG9wMTwtZmFjdG9yKGNvJHRvcDEsIGxldmVscz1jKCJQV1MiLCJUQiIsIlNTIiwiTiIpKQogICAgICAgIHltYXg8LW1heChjbyRjb3YyMywgbmEucm09VCkKICAgICAgICBnZ3Bsb3QoY28sIGFlcyh4PXN0YXJ0LzEwMDAwMDAsIHk9Y292MjMsIGNvbG9yPXRvcDEpKSsKICAgICAgICAgICAgZ2VvbV9wb2ludChzaXplPTAuNikrCiAgICAgICAgICAgIGZhY2V0X3dyYXAofmNocm9tLCBuY29sPTQpKwogICAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkreWxpbSgtMC4xLHltYXgpKwogICAgICAgICAgICB5bGFiKCJDb3ZhcmlhbmNlIikreGxhYignUG9zdGlvbiAoTWIpJykrCiAgICAgICAgICAgIGdndGl0bGUoY3ZbaV0pKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpKwogICAgICAgICAgICAjc2NhbGVfY29sb3JfZGlzY3JldGUoYnJlYWtzPWMoIlBXUyIsIlNTIiwiVEIiKSkrCiAgICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhwYXN0ZTAoY29sc1tjKDIsMSwzKV0sIkIzIiksIiNDMEMwQzA4OCIpLCBsYWJlbHM9YygiUFdTIiwiVEIiLCJTUyIsICIiKSkrCiAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGNvbG9yPWMoY29sc1tjKDIsMSwzKV0sIndoaXRlIiksIHNpemU9MiksdGl0bGU9ZWxlbWVudF90ZXh0KCJUb3AgMSUgb3V0bGllcnMiKSkpIAogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8zUG9wcy5jb3YyM19wZXJDaHJvbV8xMDBrX1dpbmRvd19PdXRsaWVycy5wbmciKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gOSwgZHBpPTMwMCkKICAgICAgICAKICAgICAgICAjYXNzaWduIGNvbG9ycwogICAgICAgIGNvJHRvcDE8LWFwcGx5KGNvLCAxLCBmdW5jdGlvbih4KSB7aWZlbHNlICh4Wyd0b3AxJ109PSJOIiwgeFsnY29sb3InXSwgeFsndG9wMSddKX0gKQogICAgICAgIGNvJHRvcDE8LWZhY3RvcihjbyR0b3AxLCBsZXZlbHM9YygiUFdTIiwiVEIiLCJTUyIsImNvbDEiLCJjb2wyIikpCiAgICAgICAgI2NvdW50IHRoZSBudW1iZXIgb2Ygc2l0ZXMgcGVyIGNocm9tb3NvbWVzCiAgICAgICAgcG9zczwtZGF0YS5mcmFtZShjaHI9cGFzdGUwKCJjaHIiLDE6MjYpKQogICAgICAgIGs9MQogICAgICAgIGZvciAoaiBpbiAxOjI2KXsKICAgICAgICAgICAgZGY8LWRmMVtkZjEkY2hyPT1wYXN0ZTAoImNociIsaiksXQogICAgICAgICAgICBwb3NzJHN0YXJ0W2pdPC1rCiAgICAgICAgICAgIHBvc3MkZW5kW2pdPC1rK25yb3coZGYpLTEKICAgICAgICAgICAgaz1rK25yb3coZGYpCiAgICAgICAgfQogICAgICAgIHBvc3MkeDwtcG9zcyRzdGFydCsocG9zcyRlbmQtcG9zcyRzdGFydCkvMgogICAgICAgIHltYXg8LW1heChjbyRjb3YsIG5hLnJtPVQpCiAgICAgICAgZ2dwbG90KGNvLCBhZXMoeD1pbmRleCwgeT1jb3YyMywgY29sb3I9dG9wMSkpKwogICAgICAgICAgICBnZW9tX3BvaW50KHNpemU9MC41KSsKICAgICAgICAgICAgdGhlbWVfY2xhc3NpYygpK3lsaW0oLTAuMSx5bWF4KSsKICAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKHBhc3RlMChjb2xzW2MoMiwxLDMpXSwiQjMiKSwiI0E4QkJDRDY2IiwiI0Q2RDZENjY2IiksIGxhYmVscz1jKCJQV1MiLCAiVEIiLCJTUyIsICIiLCIiKSkrCiAgICAgICAgICAgICAgICB5bGFiKCJDb3ZhcmlhbmNlIikrCiAgICAgICAgICAgICAgICBnZ3RpdGxlKHBhc3RlMCgiIDEwMGsgd2luZG93ICIsY3ZbaV0pKSsKICAgICAgICAgICAgICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGNvbG9yPWMoY29sc1tjKDIsMSwzKV0sIndoaXRlIiwid2hpdGUiKSwgc2l6ZT0yKSwgdGl0bGU9ZWxlbWVudF90ZXh0KCJPdXRsaWVyICgxJSkiKSkpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobmFtZT0iQ2hyb21vc29tZSIsIGJyZWFrcz1wb3NzJHgsIGxhYmVscz0xOjI2KSsKICAgICAgICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTApKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8zUG9wcy4iLGN2W2ldLCJfMTAwa19XaW5kb3dfT3V0bGllcnMucG5nIiksIHdpZHRoID0gMTAsIGhlaWdodCA9IDMuNSwgZHBpPTMwMCkKICAgICAgICB9CiAgICAgICAgCn0KCmBgYAoKIVtdKC4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8zUG9wcy5jb3YxMl9wZXJDaHJvbV8xMDBrX1dpbmRvd19PdXRsaWVycy5wbmcpCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvM1BvcHMuY292MTNfcGVyQ2hyb21fMTAwa19XaW5kb3dfT3V0bGllcnMucG5nKQoKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvM1BvcHMuY292MjNfcGVyQ2hyb21fMTAwa19XaW5kb3dfT3V0bGllcnMucG5nKSAgCgohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLzNQb3BzLmNvdjEyXzEwMGtfV2luZG93X091dGxpZXJzLnBuZykKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvM1BvcHMuY292MTNfMTAwa19XaW5kb3dfT3V0bGllcnMucG5nKQohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLzNQb3BzLmNvdjIzXzEwMGtfV2luZG93X091dGxpZXJzLnBuZykgCgojIyMgV2hvbGUgZ2Vub21lIHBsb3RzIGFsbCB0aW1lIHByaW9kcyBmb3IgUFdTIGFuZCBUQgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgUGxvdCAzIHRpbWUgcGVyaW9kcyB0b2dldGhlciBmb3IgUFdTIGFuZCBUQgpDb3Y8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgoY3YpKXsKICAgICNjdXRvZmYgdmFsdWUKICAgIHg8LWxvd3MkbG93W2xvd3MkY292PT1jdltpXV0KICAgICNQV1MKICAgIGRmMTwtY292Lmxpc3RbWyJQV1NfMTAwayJdXQogICAgZGYxPC1kZjFbb3JkZXIoZGYxWyxjdltpXV0sIGRlY3JlYXNpbmc9VCksXQogICAgZGYxJHRvcDE8LSJOIgogICAgZGYxJHRvcDFbZGYxWyxjdltpXV0+PXhdPC0iUFdTIgogICAgCiAgICAjdGIKICAgIGRmMjwtY292Lmxpc3RbWyJUQl8xMDBrIl1dCiAgICBkZjI8LWRmMltvcmRlcihkZjJbLGN2W2ldXSwgZGVjcmVhc2luZz1UKSxdCiAgICBkZjIkdG9wMTwtIk4iCiAgICBkZjIkdG9wMVtkZjJbLGN2W2ldXT49eF08LSJUQiIKICAgIAogICAgI0NvbWJpbmUgUFdTIGFuZCBUQiB0YWJsZXMKICAgIGNvPC1yYmluZChkZjEsIGRmMikKICAgIGNvJGNocm9tPC1mYWN0b3IoY28kY2hyb20sIGxldmVscz1wYXN0ZTAoImNociIsIDE6MjYpKQogICAgY29sbmFtZXMoY28pW3doaWNoKGNvbG5hbWVzKGNvKT09Y3ZbaV0pXTwtImNvdiIKICAgICNhc3NnaW4gY29sb3JzCiAgICBjbyR0b3AxPC1hcHBseShjbywgMSwgZnVuY3Rpb24oeCkge2lmZWxzZSAoeFsndG9wMSddPT0iTiIsIHhbJ2NvbG9yJ10sIHhbJ3RvcDEnXSl9ICkKICAgIGNvJHRvcDE8LWZhY3RvcihjbyR0b3AxLCBsZXZlbHM9YygiUFdTIiwiVEIiLCJjb2wxIiwiY29sMiIpKQogICAgY28kdGltZTwtY3ZbaV0KICAgIAogICAgQ292PC1yYmluZChDb3YsIGNvWyxjKCJpbmRleCIsICJjb3YiLCJ0b3AxIiwidGltZSIpXSkKfQoKI2NvdW50IHRoZSBudW1iZXIgb2Ygc2l0ZXMgcGVyIGNocm9tb3NvbWVzCmRmMTwtY292Lmxpc3RbWyJQV1NfMTAwayJdXQpwb3NzPC1kYXRhLmZyYW1lKGNocj1wYXN0ZTAoImNociIsMToyNikpCms9MQpmb3IgKGogaW4gMToyNil7CiAgICAgICAgZGY8LWRmMVtkZjEkY2hyPT1wYXN0ZTAoImNociIsaiksXQogICAgICAgIHBvc3Mkc3RhcnRbal08LWsKICAgICAgICBwb3NzJGVuZFtqXTwtaytucm93KGRmKS0xCiAgICAgICAgaz1rK25yb3coZGYpCn0KcG9zcyR4PC1wb3NzJHN0YXJ0Kyhwb3NzJGVuZC1wb3NzJHN0YXJ0KS8yCnltYXg8LW1heChjbyRjb3YsIG5hLnJtPVQpCmdncGxvdChDb3YsIGFlcyh4PWluZGV4LCB5PWNvdiwgY29sb3I9dG9wMSkpKwogICAgZmFjZXRfd3JhcCh+dGltZSwgbmNvbD0xKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjUpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsaW0oLTAuMSx5bWF4KSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YyhwYXN0ZTAoY29sc1tjKDIsMSldLCJCMyIpLCIjQThCQkNENjYiLCIjRDZENkQ2NjYiKSwgbGFiZWxzPWMoIlBXUyIsICJUQiIsICIiLCIiKSkrCiAgICB5bGFiKCJDb3ZhcmlhbmNlIikrCiAgICBndWlkZXMoY29sb3IgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChjb2xvcj1jKGNvbHNbYygyLDEpXSwid2hpdGUiLCJ3aGl0ZSIpLCBzaXplPTIpLCB0aXRsZT1lbGVtZW50X3RleHQoIk91dGxpZXIiLCBzaXplPTEwKSkpKwogICAgc2NhbGVfeF9jb250aW51b3VzKG5hbWU9IkNocm9tb3NvbWUiLCBicmVha3M9cG9zcyR4LCBsYWJlbHM9MToyNikKCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9QV1NfVEJfMTAwa19XaW5kb3dfT3V0bGllcnMucG5nIiksIHdpZHRoID0gMTEsIGhlaWdodCA9IDUsIGRwaT0zMDApCiAgICAgICAgfX0KCgpgYGAKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvUFdTX1RCXzEwMGtfV2luZG93X091dGxpZXJzLnBuZykKCgoKCiMjIE92ZXJsYXBwaW5nIG91dGxpZXIgcmVnaW9ucyBiZXR3ZWVuIGRpZmZlcmVudCBwb3B1bGF0aW9ucyAKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIzEwMGsKY3Y8LWMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpCnBhaXJzPC10KGNvbWJuKHBvcHMsIDIpKQpwYWlyczwtZGF0YS5mcmFtZShwYWlycykKY29sbmFtZXMocGFpcnMpPC1wYXN0ZTAoInBvcCIsMToyKQpPdl9kaXJlY3Q8LWRhdGEuZnJhbWUoY292PWMoY3ZbMToyXSwiY292MjMtUFQiLCJjb3YyMy1QUyIsImNvdjIzLVNUIiAsImNvdjIzLTMiKSkKT3ZfMzAwPC1kYXRhLmZyYW1lKGNvdj1jKGN2WzE6Ml0sImNvdjIzLVBUIiwiY292MjMtUFMiLCJjb3YyMy1TVCIgLCJjb3YyMy0zIikpCmZvciAoaSBpbiAxOmxlbmd0aChjdikpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLzNwb3BzX3RvcDFwZXJjZW50X291dGxpZXJfY3V0b2ZmLiIsIGN2W2ldLCAiLmNzdiIpKQogICAgZGYkaWQ8LXBhc3RlMChkZiRjaHJvbSwiXyIsZGYkc3RhcnQpCiAgICAKICAgIGlmIChpIT0zKXsKICAgICAgICAjZXhhY3Qgb3ZlcmxhcHMKICAgICAgICBpc2VjPC1pbnRlcnNlY3QoZGYkaWRbZGYkcG9wPT0iUFdTIl0sIGRmJGlkW2RmJHBvcD09IlRCIl0pIAogICAgICAgIE92X2RpcmVjdCRjb3VudFtpXTwtbGVuZ3RoKGlzZWMpCiAgICAgICAgCiAgICAgICAgIyMjIyBDaGVjayBjaHJvbW9zb21lIHJlZ2lvbiBvdmVybGFwICstMjAwLDAwMCBiYXNlcwogICAgICAgIHBvcDE8LWRmW2RmJHBvcD09IlBXUyIsXQogICAgICAgIHBvcDI8LWRmW2RmJHBvcD09IlRCIixdCiAgICAgICAgb3ZlcmxwczwtZGF0YS5mcmFtZSgpCiAgICAgICAgb3ZlcmxwczI8LWRhdGEuZnJhbWUoKQogICAgICAgIGZvciAobiBpbiAxOiBucm93KHBvcDEpKXsKICAgICAgICAgICAgcmU8LXBvcDJbcG9wMiRjaHJvbT09cG9wMSRjaHJvbVtuXSxdCiAgICAgICAgICAgIGlmIChucm93KHJlKT49MSl7CiAgICAgICAgICAgICAgICBmb3IgKHMgaW4gMTogbnJvdyhyZSkpewogICAgICAgICAgICAgICAgICAgIGlmIChyZSRzdGFydFtzXTw9cG9wMSRzdGFydFtuXSsyMDAwMDAgJiByZSRzdGFydFtzXT49cG9wMSRzdGFydFtuXS0yMDAwMDApewogICAgICAgICAgICAgICAgICAgICAgICBvdmVybHBzPC1yYmluZChvdmVybHBzLCByZVtzLF0pCiAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJscHMyPC1yYmluZChvdmVybHBzMixwb3AxW24sXSl9CiAgICAgICAgICAgICAgICB9CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgIyBNZXJnZSB0d28gdGFibGVzIGludG8gb25lIHN1bW1hcnkgb3ZlcmxhcCB0YWJsZToKICAgICAgICBvdjwtZGF0YS5mcmFtZShpZD1vdmVybHBzJGlkKQogICAgICAgIGZvciAobiBpbiAxOiBucm93KG92ZXJscHMpKXsKICAgICAgICAgICAgaWYgKG92ZXJscHMkc3RhcnRbbl08b3ZlcmxwczIkc3RhcnRbbl0pIHtvdiRzdGFydFtuXTwtb3ZlcmxwcyRzdGFydFtuXTsgb3YkZW5kW25dPC1vdmVybHBzMiRlbmRbbl19CiAgICAgICAgICAgIGlmIChvdmVybHBzJHN0YXJ0W25dPj1vdmVybHBzMiRzdGFydFtuXSkge292JHN0YXJ0W25dPC1vdmVybHBzMiRzdGFydFtuXTtvdiRlbmRbbl08LW92ZXJscHMkZW5kW25dfQogICAgICAgIH0KICAgICAgICBvdlssImNvdi5QV1MiXTwtb3Zlcmxwc1ssNF0KICAgICAgICBvdlssImNvdi5UQiJdPC1vdmVybHBzMlssNF0KICAgICAgICB3cml0ZS5jc3Yob3YsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL092ZXJsYXBfcmVnaW9uc18iLGN2W2ldLCJfcGx1c21pbnVzMTAway5jc3YiKSwgcm93Lm5hbWVzID0gRikKICAgICAgICBPdl8zMDAkY291bnRbaV08LW5yb3cob3YpCiAgICAgICAgfQogICAgICAgIAogICAgaWYgKGk9PTMpewogICAgICAgIGlzZWM8LWludGVyc2VjdChkZiRpZFtkZiRwb3A9PSJQV1MiXSwgZGYkaWRbZGYkcG9wPT0iVEIiXSkgCiAgICAgICAgaXNlYzI8LWludGVyc2VjdChkZiRpZFtkZiRwb3A9PSJQV1MiXSwgZGYkaWRbZGYkcG9wPT0iU1MiXSkgCiAgICAgICAgaXNlYzM8LWludGVyc2VjdChkZiRpZFtkZiRwb3A9PSJTUyJdLCBkZiRpZFtkZiRwb3A9PSJUQiJdKSAKICAgICAgICBPdl9kaXJlY3QkY291bnRbaV08LWxlbmd0aChpc2VjKQogICAgICAgIE92X2RpcmVjdCRjb3VudFtpKzFdPC1sZW5ndGgoaXNlYzIpCiAgICAgICAgT3ZfZGlyZWN0JGNvdW50W2krMl08LWxlbmd0aChpc2VjMykKICAgICAgICBPdl9kaXJlY3QkY291bnRbaSszXTwtbGVuZ3RoKGludGVyc2VjdChkZiRpZFtkZiRwb3A9PSJTUyJdLCBpbnRlcnNlY3QoZGYkaWRbZGYkcG9wPT0iUFdTIl0sIGRmJGlkW2RmJHBvcD09IlRCIl0pKSkKICAgICAgICAKICAgICAgICBmb3IoaiBpbiAxOm5yb3cocGFpcnMpKXsKICAgICAgICAjIyMjIENoZWNrIGNocm9tb3NvbWUgcmVnaW9uIG92ZXJsYXAgKy0yMDAsMDAwIGJhc2VzCiAgICAgICAgICAgIHBvcDE8LWRmW2RmJHBvcD09cGFpcnNbaiwxXSxdCiAgICAgICAgICAgIHBvcDI8LWRmW2RmJHBvcD09cGFpcnNbaiwyXSxdCiAgICAgICAgICAgIG92ZXJscHM8LWRhdGEuZnJhbWUoKQogICAgICAgICAgICBvdmVybHBzMjwtZGF0YS5mcmFtZSgpCiAgICAgICAgICAgIGZvciAobiBpbiAxOiBucm93KHBvcDEpKXsKICAgICAgICAgICAgICAgIHJlPC1wb3AyW3BvcDIkY2hyb209PXBvcDEkY2hyb21bbl0sXQogICAgICAgICAgICAgICAgaWYgKG5yb3cocmUpPj0xKXsKICAgICAgICAgICAgICAgICAgICBmb3IgKHMgaW4gMTogbnJvdyhyZSkpewogICAgICAgICAgICAgICAgICAgICAgICBpZiAocmUkc3RhcnRbc108PXBvcDEkc3RhcnRbbl0rMjAwMDAwICYgcmUkc3RhcnRbc10+PXBvcDEkc3RhcnRbbl0tMjAwMDAwKXsKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJscHM8LXJiaW5kKG92ZXJscHMsIHJlW3MsXSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG92ZXJscHMyPC1yYmluZChvdmVybHBzMixwb3AxW24sXSl9CiAgICAgICAgICAgICAgICAgICAgfQogICAgICAgICAgICAgICAgfQogICAgICAgICAgICB9CiAgICAgICAgIyBNZXJnZSB0d28gdGFibGVzIGludG8gb25lIHN1bW1hcnkgb3ZlcmxhcCB0YWJsZToKICAgICAgICAgICAgb3Y8LWRhdGEuZnJhbWUoaWQ9b3ZlcmxwcyRpZCkKICAgICAgICAgICAgZm9yIChuIGluIDE6IG5yb3cob3ZlcmxwcykpewogICAgICAgICAgICAgICAgaWYgKG92ZXJscHMkc3RhcnRbbl08b3ZlcmxwczIkc3RhcnRbbl0pIHtvdiRzdGFydFtuXTwtb3ZlcmxwcyRzdGFydFtuXTsgb3YkZW5kW25dPC1vdmVybHBzMiRlbmRbbl19CiAgICAgICAgICAgICAgICBpZiAob3ZlcmxwcyRzdGFydFtuXT49b3ZlcmxwczIkc3RhcnRbbl0pIHtvdiRzdGFydFtuXTwtb3ZlcmxwczIkc3RhcnRbbl07b3YkZW5kW25dPC1vdmVybHBzJGVuZFtuXX0KICAgICAgICAgICAgfQogICAgICAgIAogICAgICAgICAgICBvdlsscGFzdGUwKCJjb3YuIixwYWlyc1tqLDFdKV08LW92ZXJscHNbLDRdCiAgICAgICAgICAgIG92WyxwYXN0ZTAoImNvdi4iLHBhaXJzW2osMl0pXTwtb3ZlcmxwczJbLDRdCiAgICAgICAgICAgIG92PC1vdlshZHVwbGljYXRlZChvdiksXQogICAgICAgICAgICB3cml0ZS5jc3Yob3YsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL092ZXJsYXBfcmVnaW9uc18iLGN2W2ldLCJfIixwYWlyc1tqLDFdLCIuIiwgcGFpcnNbaiwyXSwiX3BsdXNtaW51czIwMGsuY3N2IiksIHJvdy5uYW1lcyA9IEYpCiAgICAgICAgICAgIE92XzMwMCRjb3VudFtpK2otMV08LW5yb3cob3YpCiAgICB9CiAgICB9Cn0Kd3JpdGUuY3N2KE92X2RpcmVjdCwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvRGlyZWN0X092ZXJsYXBwaW5nX3JlZ2lvbnNfY291bnRzXzNwb3Bfc3VtbWFyeS5jc3YiKSkKT3ZfMzAwJGNvdW50WzZdPC1OQQp3cml0ZS5jc3YoT3ZfMzAwLCBwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9PdmVybGFwcGluZ19yZWdpb25zX2NvdW50c18zcG9wX3BsdXNNaW51czIwMGsuY3N2IikpCgpgYGAKCgojIFJ1biB0aGUgc25wRWZmIHBpcGVsaW5lIHRvIGZpbmQgYW5ub3RhdGlvbiBpbiB0aGUgb3V0bGllciByZWdpb25zICgxMDBrLXdpbmRvdystMTAwaykgIAoKIyMgQ3JlYXRlIGEgc2NyaXB0IHRvIHJ1biBTbnBFZmYgCgpDcmVhdGUgVkNGIGZpbGVzIHdpdGggc2VsZWN0ZWQgcmVnaW9ucyAmIHJ1biBzbnBFZmYgIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ3JlYXRlIGJlZCBmaWxlcwpjdjwtYygiY292MTIiLCJjb3YxMyIsImNvdjIzIikKI1ByZXZlbnQgc2NpZW50aWZpYyBub3RhdGlvbiBpbiBiZWQgZmlsZXMKb3B0aW9ucyhzY2lwZW49OTk5KQoKI1RoZSBmaXJzdCBsaW5lIG9mIGJlZCBmaWxlcyBpcyBvZnRlbiBub3QgcmVkIGJ5IHZjZnRvb2xzCmZvciAoaSBpbiAxOjMpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLzNwb3BzX3RvcDFwZXJjZW50X291dGxpZXJfY3V0b2ZmLiIsIGN2W2ldLCAiLmNzdiIpKQogICAgI2FkZCAxMDBrCiAgICBkZiRzdGFydDwtZGYkc3RhcnQtMTAwMDAwCiAgICBkZiRlbmQ8LWRmJGVuZCsxMDAwMDAKICAgIGRmcDwtZGZbZGYkcG9wPT0iUFdTIiwxOjNdCiAgICBjb2xuYW1lcyhkZnApPC1jKCd0cmFjayB0eXBlPWJlZEdyYXBoJywgJzEnLCcxJykKICAgIHdyaXRlLnRhYmxlKGRmcCwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvUFdTX291dGxpZXJzXyIsY3ZbaV0sIl9uZXcuYmVkIikscXVvdGUgPSBGLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBULHNlcCA9ICJcdCIpCiAgICBkZnQ8LWRmW2RmJHBvcD09IlRCIiwxOjNdCiAgICBjb2xuYW1lcyhkZnQpPC1jKCd0cmFjayB0eXBlPWJlZEdyYXBoJywgJzEnLCcxJykKICAgIHdyaXRlLnRhYmxlKGRmdCwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVEJfb3V0bGllcnNfIixjdltpXSwiX25ldy5iZWQiKSxxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsc2VwID0gIlx0IikKICAgIAogICAgaWYgKGk9PTMpewogICAgICAgIGRmczwtZGZbZGYkcG9wPT0iU1MiLDE6M10KICAgICAgICBjb2xuYW1lcyhkZnMpPC1jKCd0cmFjayB0eXBlPWJlZEdyYXBoJywgJzEnLCcxJykKICAgICAgICB3cml0ZS50YWJsZShkZnMsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1NTX291dGxpZXJzXyIsY3ZbaV0sIl9uZXcuYmVkIikscXVvdGUgPSBGLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHNlcCA9ICJcdCIpCiAgICB9Cn0KCiMgQ3JlYXRlIGEgYmFzaCBzY3JpcHQgdG8gY3JlYXRlIHZjZiBmaWxlcyB3aXRoIHNlbGVjdGVkIHJlZ2lvbnMKYmVkZmlsZXM8LWxpc3QuZmlsZXMoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLCBwYXR0ZXJuPSIqX25ldy5iZWQiKQoKc2luaygiLi4vQ09Wc2Nhbl9jcmVhdGVWQ0ZzXzNQb3BzX2N1dG9mZi5zaCIpCmNhdCgiIyEvYmluL2Jhc2ggXG5cbiIpCmZvciAoaSBpbiAxOmxlbmd0aChiZWRmaWxlcykpewogICAgZm5hbWU8LWdzdWIoIi5iZWQiLCcnLCBiZWRmaWxlc1tpXSkKICAgIGNhdChwYXN0ZTAoInZjZnRvb2xzIC0tZ3p2Y2YgRGF0YS9uZXdfdmNmLzNwb3AvM3BvcHMuTUQ3MDAwX05TMC41X21hZjA1LnZjZi5neiAtLWJlZCBPdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIiwgYmVkZmlsZXNbaV0sICIgLS1vdXQgT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsIGZuYW1lLCIgLS1yZWNvZGUgLS1rZWVwLUlORk8tYWxsIFxuIikpCn0Kc2luayhOVUxMKSAgCmBgYAoKCiMjIyBDcmVhdGUgYmVkIGZpbGVzIGFuZCBzY3JpcHRzIHRvIHJ1biBTbnBFZmYgd2l0aCBsZXNzIHBhZGRlZCB3aW5kb3dzICgxMGspCgpDcmVhdGUgVkNGIGZpbGVzIHdpdGggc2VsZWN0ZWQgcmVnaW9ucyAmIHJ1biBzbnBFZmYgIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ3JlYXRlIGJlZCBmaWxlcwpjdjwtYygiY292MTIiLCJjb3YxMyIsImNvdjIzIikKI1ByZXZlbnQgc2NpZW50aWZpYyBub3RhdGlvbiBpbiBiZWQgZmlsZXMKb3B0aW9ucyhzY2lwZW49OTk5KQoKI1RoZSBmaXJzdCBsaW5lIG9mIGJlZCBmaWxlcyBpcyBvZnRlbiBub3QgcmVkIGJ5IHZjZnRvb2xzCmZvciAoaSBpbiAxOjMpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLzNwb3BzX3RvcDFwZXJjZW50X291dGxpZXJfY3V0b2ZmLiIsIGN2W2ldLCAiLmNzdiIpKQogICAgI2FkZCAxMGsKICAgIGRmJHN0YXJ0PC1kZiRzdGFydC0xMDAwMAogICAgZGYkZW5kPC1kZiRlbmQrMTAwMDAKICAgIGRmcDwtZGZbZGYkcG9wPT0iUFdTIiwxOjNdCiAgICBjb2xuYW1lcyhkZnApPC1jKCd0cmFjayB0eXBlPWJlZEdyYXBoJywgJzEnLCcxJykKICAgIHdyaXRlLnRhYmxlKGRmcCwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvUFdTX291dGxpZXJzXyIsY3ZbaV0sIl8xMGtwYWQuYmVkIikscXVvdGUgPSBGLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBULHNlcCA9ICJcdCIpCiAgICBkZnQ8LWRmW2RmJHBvcD09IlRCIiwxOjNdCiAgICBjb2xuYW1lcyhkZnQpPC1jKCd0cmFjayB0eXBlPWJlZEdyYXBoJywgJzEnLCcxJykKICAgIHdyaXRlLnRhYmxlKGRmdCwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVEJfb3V0bGllcnNfIixjdltpXSwiXzEwa3BhZC5iZWQiKSxxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYsc2VwID0gIlx0IikKICAgIAogICAgaWYgKGk9PTMpewogICAgICAgIGRmczwtZGZbZGYkcG9wPT0iU1MiLDE6M10KICAgICAgICBjb2xuYW1lcyhkZnMpPC1jKCd0cmFjayB0eXBlPWJlZEdyYXBoJywgJzEnLCcxJykKICAgICAgICB3cml0ZS50YWJsZShkZnMsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1NTX291dGxpZXJzXyIsY3ZbaV0sIl8xMGtwYWQuYmVkIikscXVvdGUgPSBGLCByb3cubmFtZXMgPSBGLCBjb2wubmFtZXMgPSBGLHNlcCA9ICJcdCIpCiAgICB9Cn0KCiMgQ3JlYXRlIGEgYmFzaCBzY3JpcHQgdG8gY3JlYXRlIHZjZiBmaWxlcyB3aXRoIHNlbGVjdGVkIHJlZ2lvbnMKYmVkZmlsZXM8LWxpc3QuZmlsZXMoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLCBwYXR0ZXJuPSIqXzEwa3BhZC5iZWQiKQoKc2luaygiLi4vQ09Wc2Nhbl9jcmVhdGVWQ0ZzXzNQb3BzX2N1dG9mZl8xMGtwYWQuc2giKQpjYXQoIiMhL2Jpbi9iYXNoIFxuXG4iKQpmb3IgKGkgaW4gMTpsZW5ndGgoYmVkZmlsZXMpKXsKICAgIGZuYW1lPC1nc3ViKCIuYmVkIiwnJywgYmVkZmlsZXNbaV0pCiAgICBjYXQocGFzdGUwKCJ2Y2Z0b29scyAtLWd6dmNmIERhdGEvbmV3X3ZjZi8zcG9wLzNwb3BzLk1ENzAwMF9OUzAuNV9tYWYwNS52Y2YuZ3ogLS1iZWQgT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsIGJlZGZpbGVzW2ldLCAiIC0tb3V0IE91dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLCBmbmFtZSwiIC0tcmVjb2RlIC0ta2VlcC1JTkZPLWFsbCBcbiIpKQp9CnNpbmsoTlVMTCkgIApgYGAKCgpgYGB7YmFzaCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpjZCB+L1Byb2plY3RzL1BhY0hlcnJpbmcKYmFzaCBDT1ZzY2FuX2NyZWF0ZVZDRnNfM3BvcHMuc2gKYGBgCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NyZWF0ZSBhIGJhc2ggc2NyaXB0IHRvIHJ1biBzbnBFZmYKdmZpbGVzPC1saXN0LmZpbGVzKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIiwgcGF0dGVybj0iLnJlY29kZS52Y2YiKQoKc2luaygifi9wcm9ncmFtcy9zbnBFZmYvcnVuc25wRWZmX2Nvdl8zcG9wX2N1dG9mZi5zaCIpCmNhdCgiIyEvYmluL2Jhc2ggXG5cbiIpCmZvciAoaSBpbiAxOmxlbmd0aCh2ZmlsZXMpKXsKICAgIGZuYW1lPC1nc3ViKCJfbmV3LnJlY29kZS52Y2YiLCIiLHZmaWxlc1tpXSkKICAgIGNhdChwYXN0ZTAoImphdmEgLVhteDhnIC1qYXIgc25wRWZmLmphciBDaF92Mi4wLjIuOTkgfi9Qcm9qZWN0cy9QYWNIZXJyaW5nL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLHZmaWxlc1tpXSwgIiAtc3RhdHMgfi9Qcm9qZWN0cy9QYWNIZXJyaW5nL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLGZuYW1lLCIuaHRtbCA+ICB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0Fubm8uIixmbmFtZSwiLnZjZiBcbiIpKQogICAgCiAgICAjZXh0cmFjdCB0aGUgYW5ub3RhdGlvbiBpbmZvcm1hdGlvbgogICAgY2F0KHBhc3RlMCgiYmNmdG9vbHMgcXVlcnkgLWYgJyVDSFJPTSAlUE9TICVJTkZPL0FGICVJTkZPL0FOTlxcbicgfi9Qcm9qZWN0cy9QYWNIZXJyaW5nL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9Bbm5vLiIsZm5hbWUsIi52Y2YgPiB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsZm5hbWUsIl9hbm5vdGF0aW9uIFxuXG4iKSkKCn0Kc2luayhOVUxMKSAgCgoKIyMgZm9yIDEwayBwYWQgdmNmCgojY3JlYXRlIGEgYmFzaCBzY3JpcHQgdG8gcnVuIHNucEVmZgp2ZmlsZXM8LWxpc3QuZmlsZXMoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLCBwYXR0ZXJuPSIxMGtwYWQucmVjb2RlLnZjZiIpCgpzaW5rKCJ+L3Byb2dyYW1zL3NucEVmZi9ydW5zbnBFZmZfY292XzNwb3BfY3V0b2ZmXzEwa3BhZC5zaCIpCmNhdCgiIyEvYmluL2Jhc2ggXG5cbiIpCmZvciAoaSBpbiAxOmxlbmd0aCh2ZmlsZXMpKXsKICAgIGZuYW1lPC1nc3ViKCIucmVjb2RlLnZjZiIsIiIsdmZpbGVzW2ldKQogICAgY2F0KHBhc3RlMCgiamF2YSAtWG14OGcgLWphciBzbnBFZmYuamFyIENoX3YyLjAuMi45OSB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsdmZpbGVzW2ldLCAiIC1zdGF0cyB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsZm5hbWUsIi5odG1sID4gIH4vUHJvamVjdHMvUGFjSGVycmluZy9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvQW5uby4iLGZuYW1lLCIudmNmIFxuIikpCiAgICAKICAgICNleHRyYWN0IHRoZSBhbm5vdGF0aW9uIGluZm9ybWF0aW9uCiAgICBjYXQocGFzdGUwKCJiY2Z0b29scyBxdWVyeSAtZiAnJUNIUk9NICVQT1MgJUlORk8vQUYgJUlORk8vQU5OXFxuJyB+L1Byb2plY3RzL1BhY0hlcnJpbmcvT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0Fubm8uIixmbmFtZSwiLnZjZiA+IH4vUHJvamVjdHMvUGFjSGVycmluZy9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIixmbmFtZSwiX2Fubm90YXRpb24gXG5cbiIpKQoKfQpzaW5rKE5VTEwpICAKCgoKYGBgCgpgYGB7YmFzaCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpjZCB+L3Byb2dyYW1zL3NucEVmZgpiYXNoIHJ1bnNucEVmZl9jb3ZfM3BvcF9jdXRvZmYuc2gKYGBgCgoKCiMjIENyZWF0ZSBzdW1tYXJ5IGdlbmUgZmlsZXMgZnJvbSBzbnBFZmYgYW5kIGNoZWNrIG92ZXJsYXBwaW5nIGdlbmVzLgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgQ3JlYXRlIHN1bW1hcnkgZmlsZXMgb2Ygc25wRWZmIHJlc3VsdHMgKGdlbmUgYW5ub3RhdGlvbnMgaW4gdGhlIHJlZ2lvbnMgb2YgaW50ZXJlc3QpIGFuZCByZWZvcm1hdCBhcyBhIFNoaW55R28gaW5wdXQgCgojY3JlYXRlIGdlbmUgbGlzdCAKZ2ZpbGVzPC1saXN0LmZpbGVzKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIiwgcGF0dGVybj0iZ2VuZXMudHh0IikKCmZvciAoaSBpbiAxOmxlbmd0aChnZmlsZXMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsZ2ZpbGVzW2ldKSwgc2VwPSJcdCIpCiAgICBkZjwtZGZbLDE6N10KICAgIGNvbG5hbWVzKGRmKTwtYygiR2VuZU5hbWUiLCJHZW5lSWQiLCJUcmFuc2NyaXB0SWQiLCJCaW9UeXBlIiwidmFyaWFudHNfaW1wYWN0X0hJR0giLCJ2YXJpYW50c19pbXBhY3RfTE9XIiwJInZhcmlhbnRzX2ltcGFjdF9NT0RFUkFURSIpCiAgICAKICAgIGZuYW1lPC1nc3ViKCIuZ2VuZXMudHh0IiwiIixnZmlsZXNbaV0pCiAgICBnZW5lczwtdW5pcXVlKGRmJEdlbmVJZCkKICAgIHNpbmsocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvZ2VuZUlEbGlzdF8iLGZuYW1lLCIudHh0IikpCiAgICBjYXQocGFzdGUwKGdlbmVzLCI7ICIpKQogICAgc2luayhOVUxMKQp9CgojQW5ub3RhdGlvbiBpbmZvciBmcm9tIFNucEVmZgpjdjwtYygiY292MTIiLCJjb3YxMyIsImNvdjIzIikKZm9yIChjIGluIDE6Myl7CiAgICBpZiAoYyE9Myl7CiAgICBmb3IgKHAgaW4gMToyKXsKICAgICAgICBhbm88LXJlYWQudGFibGUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIixwb3BzW3BdLCJfb3V0bGllcnNfIixjdltjXSwiX2Fubm90YXRpb24iKSwgaGVhZGVyID0gRikKICAgICAgICBhbm5vdGF0aW9uczwtZGF0YS5mcmFtZSgpCiAgICAgICAgZm9yIChpIGluIDE6IG5yb3coYW5vKSl7CiAgICAgICAgICAgIGFubnM8LXVubGlzdChzdHJzcGxpdChhbm8kVjRbaV0sICJcXCx8XFx8IikpCiAgICAgICAgICAgIGFubm08LWRhdGEuZnJhbWUobWF0cml4KGFubnMsbmNvbCA9IDE2LCBieXJvdyA9IFRSVUUpKQogICAgICAgICAgICBhbm5tPC1hbm5tWyxjKDIsMyw0LDUsOCldCiAgICAgICAgICAgIGNvbG5hbWVzKGFubm0pPC1jKCJFZmZlY3QiLCJQdXRhdGl2ZV9pbXBhY3QiLCJHZW5lX25hbWUiLCJHZW5lX0lEIiwiRmVhdHVyZSB0eXBlIikKICAgICAgICAgICAgYW5ubTwtYW5ubVshZHVwbGljYXRlZChhbm5tKSwgXQogICAgICAgICAgICBhbm5tJGNocjwtYW5vJFYxW2ldCiAgICAgICAgICAgIGFubm0kcG9zPC1hbm8kVjJbaV0KICAgICAgICAgICAgYW5ubSRBRjwtIGFubyRWM1tpXQogICAgICAgICAgICBhbm5vdGF0aW9uczwtcmJpbmQoYW5ub3RhdGlvbnMsIGFubm0pCiAgICAgICAgfSAgICAgCiAgICAgICAgYW5ub3RhdGlvbnM8LWFubm90YXRpb25zWyxjKDY6OCwxOjUpXQogICAgICAgIGFubm90YXRpb25zPC1hbm5vdGF0aW9uc1shZHVwbGljYXRlZChhbm5vdGF0aW9uc1ssMToyXSksXQogICAgICAgIHdyaXRlLmNzdihhbm5vdGF0aW9ucywgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvR2VuZXNfIixwb3BzW3BdLCJfb3V0bGllcnNfMTAwa18iLGN2W2NdLCIuY3N2IiksIHJvdy5uYW1lcyA9IEYpCiAgICB9CiAgICB9CiAgICBpZiAoYz09Myl7CiAgICAgICAgZm9yIChwIGluIDE6Myl7CiAgICAgICAgYW5vPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIscG9wc1twXSwiX291dGxpZXJzXyIsY3ZbY10sIl9hbm5vdGF0aW9uIiksIGhlYWRlciA9IEYpCiAgICAgICAgYW5ub3RhdGlvbnM8LWRhdGEuZnJhbWUoKQogICAgICAgIGZvciAoaSBpbiAxOiBucm93KGFubykpewogICAgICAgICAgICBhbm5zPC11bmxpc3Qoc3Ryc3BsaXQoYW5vJFY0W2ldLCAiXFwsfFxcfCIpKQogICAgICAgICAgICBhbm5tPC1kYXRhLmZyYW1lKG1hdHJpeChhbm5zLG5jb2wgPSAxNiwgYnlyb3cgPSBUUlVFKSkKICAgICAgICAgICAgYW5ubTwtYW5ubVssYygyLDMsNCw1LDgpXQogICAgICAgICAgICBjb2xuYW1lcyhhbm5tKTwtYygiRWZmZWN0IiwiUHV0YXRpdmVfaW1wYWN0IiwiR2VuZV9uYW1lIiwiR2VuZV9JRCIsIkZlYXR1cmUgdHlwZSIpCiAgICAgICAgICAgIGFubm08LWFubm1bIWR1cGxpY2F0ZWQoYW5ubSksIF0KICAgICAgICAgICAgYW5ubSRjaHI8LWFubyRWMVtpXQogICAgICAgICAgICBhbm5tJGNocjwtYW5vJFYxW2ldCiAgICAgICAgICAgIGFubm0kcG9zPC1hbm8kVjJbaV0KICAgICAgICAgICAgYW5ubSRBRjwtIGFubyRWM1tpXQogICAgICAgICAgICBhbm5vdGF0aW9uczwtcmJpbmQoYW5ub3RhdGlvbnMsIGFubm0pCiAgICAgICAgfSAgICAgCiAgICAgICAgYW5ub3RhdGlvbnM8LWFubm90YXRpb25zWyxjKDY6OCwxOjUpXQogICAgICAgIGFubm90YXRpb25zPC1hbm5vdGF0aW9uc1shZHVwbGljYXRlZChhbm5vdGF0aW9uc1ssMToyXSksXQogICAgICAgIHdyaXRlLmNzdihhbm5vdGF0aW9ucywgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvR2VuZXNfIixwb3BzW3BdLCJfb3V0bGllcnNfMTAwa18iLGN2W2NdLCIuY3N2IiksIHJvdy5uYW1lcyA9IEYpCiAgICB9Cn0KICAKfQoKYGBgCgoKIyMjIGZvciAxMGsgcGFkIGRhdGEKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIENyZWF0ZSBzdW1tYXJ5IGZpbGVzIG9mIHNucEVmZiByZXN1bHRzIChnZW5lIGFubm90YXRpb25zIGluIHRoZSByZWdpb25zIG9mIGludGVyZXN0KSBhbmQgcmVmb3JtYXQgYXMgYSBTaGlueUdvIGlucHV0IAoKI2NyZWF0ZSBnZW5lIGxpc3QgCmdmaWxlczwtbGlzdC5maWxlcygiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsIHBhdHRlcm49IjEwa3BhZC5nZW5lcy50eHQiKQpmb3IgKGkgaW4gMTpsZW5ndGgoZ2ZpbGVzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi8iLGdmaWxlc1tpXSksIHNlcD0iXHQiKQogICAgZGY8LWRmWywxOjddCiAgICBjb2xuYW1lcyhkZik8LWMoIkdlbmVOYW1lIiwiR2VuZUlkIiwiVHJhbnNjcmlwdElkIiwiQmlvVHlwZSIsInZhcmlhbnRzX2ltcGFjdF9ISUdIIiwidmFyaWFudHNfaW1wYWN0X0xPVyIsCSJ2YXJpYW50c19pbXBhY3RfTU9ERVJBVEUiKQogICAgCiAgICBmbmFtZTwtZ3N1YigiLmdlbmVzLnR4dCIsIiIsZ2ZpbGVzW2ldKQogICAgZ2VuZXM8LXVuaXF1ZShkZiRHZW5lSWQpCiAgICBzaW5rKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL2dlbmVJRGxpc3RfIixmbmFtZSwiLnR4dCIpKQogICAgY2F0KHBhc3RlMChnZW5lcywiOyAiKSkKICAgIHNpbmsoTlVMTCkKfQoKCiMjIyBubyBlbnJpY2htZW50IGZvdW5kIGZyb20gMTBrIHBhZCAoUFdTLWNvdjEyKQpgYGAKCgoKCgoKIyMgRmluZCB0aGUgb3ZlcmxhcHBpbmcgZ2VuZSBuYW1lcyAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpnbmFtZXNmaWxlczwtbGlzdC5maWxlcygiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsIHBhdHRlcm49IkdlbmVzXy4rb3V0bGllcnNfMTAway4rXFxkLmNzdiQiKQoKZm9yIChpIGluIDE6bGVuZ3RoKGduYW1lc2ZpbGVzKSl7CiAgICBkZjwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIixnbmFtZXNmaWxlc1tpXSkpCiAgICBkZjwtZGZbLGMoMSw2OjcpXQogICAgZGY8LWRmWyFkdXBsaWNhdGVkKGRmKSxdCiAgICAKICAgIGZuYW1lPC1nc3ViKCIuY3N2IiwiIiwgZ25hbWVzZmlsZXNbaV0pCiAgICBmbmFtZTwtZ3N1YigiR2VuZXNfIiwiIiwgZm5hbWUpCiAgICAKICAgIAogICAgI2FkZCBnZW5lIG5hbWVzIGZvciBmcm9udCBhbmQgYmFjayBvZiBpbnRlcmdlbmljIHJlZ2lvbnMKICAgIGRmMjwtZGZbZ3JlcCgiLSIsIGRmJEdlbmVfSUQpLF0KICAgIGs9MQogICAgZGZfZGl2PC1kYXRhLmZyYW1lKCkKICAgIG9kZG5hbWVzPC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaiBpbiAxOm5yb3coZGYyKSl7CiAgICAgICAgbmFtZXM8LXVubGlzdChzdHJzcGxpdChkZjIkR2VuZV9uYW1lW2pdLCAiLSIpKQogICAgICAgIGlkczwtdW5saXN0KHN0cnNwbGl0KGRmMiRHZW5lX0lEW2pdLCAiLSIpKQogICAgICAgIAogICAgICAgIGlmIChsZW5ndGgobmFtZXMpPT0yKXsKICAgICAgICAgICAgZGZfZGl2PC1yYmluZChkZl9kaXYsIGMoZGYyJGNocltqXSxuYW1lc1sxXSxpZHNbMV0pKQogICAgICAgICAgICBrPWsrMQogICAgICAgICAgICBkZl9kaXY8LXJiaW5kKGRmX2RpdiwgYyhkZjIkY2hyW2pdLG5hbWVzWzJdLGlkc1syXSkpCiAgICAgICAgICAgIGs9aysxCiAgICAgICAgfQogICAgICAgCiAgICAgICAgaWYgKGxlbmd0aChuYW1lcykhPTIpewogICAgICAgICAgICBuPC1ncmVwKCJzaToiLCBuYW1lcykKICAgICAgICAgICAgaWYgKGxlbmd0aChuKT4wKXsKICAgICAgICAgICAgICAgIGlmIChuPT0xKSBuZXduYW1lczwtYyhwYXN0ZTAobmFtZXNbMV0sIi0iLG5hbWVzWzJdKSwgbmFtZXNbM10pCiAgICAgICAgICAgICAgICBpZiAobj09MikgbmV3bmFtZXM8LWMobmFtZXNbMV0scGFzdGUwKG5hbWVzWzJdLCItIixuYW1lc1szXSkpCiAgICAgICAgICAgICAgICBkZl9kaXY8LXJiaW5kKGRmX2RpdiwgYyhkZjIkY2hyW2pdLG5ld25hbWVzWzFdLGlkc1sxXSkpCiAgICAgICAgICAgICAgICBrPWsrMQogICAgICAgICAgICAgICAgZGZfZGl2PC1yYmluZChkZl9kaXYsIGMoZGYyJGNocltqXSxuZXduYW1lc1syXSxpZHNbMl0pKQogICAgICAgICAgICAgICAgaz1rKzEKICAgICAgICAgICAgfQogICAgICAgICAgICAKICAgICAgICAgICAgaWYgKGxlbmd0aChuKT09MCkgewogICAgICAgICAgICAgICAgb2RkbmFtZXM8LXJiaW5kKG9kZG5hbWVzLCBkZjJbaixdKQogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQogICAgZGZfZGl2PC1kZl9kaXZbIWR1cGxpY2F0ZWQoZGZfZGl2KSxdCiAgICBkZl9kaXY8LWRmX2RpdltkZl9kaXYkR2VuZV9JRCE9IkNIUl9FTkQiLF0KICAgIGRmX2RpdjwtZGZfZGl2W2RmX2RpdiRHZW5lX0lEIT0iQ0hSX1NUQVJUIixdCiAgICAKICAgIHJlbW92ZTwtZ3JlcCgiLSIsIGRmJEdlbmVfSUQpCiAgICBkZjwtZGZbLXJlbW92ZSxdCiAgICBkZjwtcmJpbmQoZGYsIGRmX2RpdikKICAgIGRmPC1kZlshZHVwbGljYXRlZChkZiksXQogICAgCiAgICBpZiAobnJvdyhvZGRuYW1lcykhPTApewogICAgICAgIHdyaXRlLmNzdihkZiwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvIixmbmFtZSwiR2VuZUxpc3Rfd2l0aEludGVyZ2VuaWNHZW5lcy5jc3YiICksIHJvdy5uYW1lcyA9IEYpCiAgICAgICAgd3JpdGUuY3N2KG9kZG5hbWVzLCBwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9PZGRuYW1lc18iLCBmbmFtZSwiLmNzdiIpKQogICAgfQogICAgaWYgKG5yb3cob2RkbmFtZXMpPT0wKXsKICAgICAgICB3cml0ZS5jc3YoZGYsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmLyIsZm5hbWUsIkdlbmVMaXN0X3dpdGhJbnRlcmdlbmljR2VuZXNfbmV3LmNzdiIgKSwgcm93Lm5hbWVzID0gRikKICAgICB9Cn0KICAgCgojIyAhISAjIwojIyBNYW51YWxseSBjaGFuZ2UgdGhlIG9kZG5hbWVzIGFuZCBhZGQgdGhlbSB0byB0aGUgR2VuZUxpc3QgKFhYLkdlbmVMaXN0X3dpdGhJbnRlcmdlbmljR2VuZXMuY3N2KSBmaWxlcyAKIyBBZGQgdGhlIGdlbmUgSURzIHRvIGdlbmVJRGxpc3RfWFhfb3V0bGllcnNfY292eHgudHh0IGZpbGVzIGFzIHdlbGwgLW9ubHkgb25lIG5lZWRzIHRvIGJlIHVwZGF0ZWQgaXMgVEIgY292MTMKIyh1cGRhdGVkIGZpbGUgbmFtZXMgaGFzICJfbmV3IiBhdCB0aGUgZW5kKQoKI2FnZ3JlZ2F0ZSBhbGwgZ2VuZSBuYW1lcwpnbmV3PC1saXN0LmZpbGVzKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC8iLCBwYXR0ZXJuPSJHZW5lTGlzdF93aXRoSW50ZXJnZW5pY0dlbmVzX25ldy5jc3YkIikKR2VuZXM8LWRhdGEuZnJhbWUoKQpHZW5lTGlzdDwtbGlzdCgpCmZvciAoaSBpbiAxOmxlbmd0aChnbmV3KSl7CiAgICBkZjwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC8iLCBnbmV3W2ldKSkKICAgIEdlbmVMaXN0W1tpXV08LWRmCiAgICBmbmFtZTwtZ3N1YigiR2VuZUxpc3Rfd2l0aEludGVyZ2VuaWNHZW5lc19uZXcuY3N2IiwnJyxnbmV3W2ldKQogICAgbmFtZXMoR2VuZUxpc3QpW2ldPC1mbmFtZQogICAgZHVwPC1kZltkdXBsaWNhdGVkKGRmKSxdCiAgICBkZjwtZGZbIWR1cGxpY2F0ZWQoZGYpLF0KICAgIEdlbmVzPC1yYmluZChHZW5lcywgZGYpCiAgICBHZW5lczwtR2VuZXNbIWR1cGxpY2F0ZWQoR2VuZXMpLF0KICAgIAp9CgoKIzEuIEJldHdlZW4gcG9wdWxhdGlvbnMKdGltZXM8LWMoImNvdjEyIiwiY292MTMiLCJjb3YyMyIpCmNvbW1vbjwtbGlzdCgpCmNvbW1vbl9zdW1tYXJ5PC1kYXRhLmZyYW1lKHRpbWU9dGltZXMpCmZvciAoaSBpbiAxOjMpewogICAgdGxpc3Q8LUdlbmVMaXN0W2dyZXAodGltZXNbaV0sIG5hbWVzKEdlbmVMaXN0KSldCiAgICBpZiAoaSAhPTMpewogICAgICAgIGNvbW1vbl9nZW5lczwtaW50ZXJzZWN0KHRsaXN0W1sxXV1bIkdlbmVfbmFtZSJdLCB0bGlzdFtbMl1dWyJHZW5lX25hbWUiXSkKICAgICAgICBjb21tb25bW2ldXTwtY29tbW9uX2dlbmVzCiAgICAgICAgbmFtZXMoY29tbW9uKVtbaV1dPC10aW1lc1tpXQogICAgICAgIGNvbW1vbl9zdW1tYXJ5JFBXU1tpXTwtbnJvdyh0bGlzdFtbZ3JlcCgiUFdTIiwgbmFtZXModGxpc3QpKV1dKQogICAgICAgIGNvbW1vbl9zdW1tYXJ5JFRCW2ldPC1ucm93KHRsaXN0W1tncmVwKCJUQiIsIG5hbWVzKHRsaXN0KSldXSkKICAgICAgICBjb21tb25fc3VtbWFyeSRTU1tpXTwtTkEKICAgICAgICBjb21tb25fc3VtbWFyeSRjb21tb25fUFdTLlRCW2ldPC1ucm93KGNvbW1vbl9nZW5lcykKICAgICAgICAKICAgICAgICBwd3M8LXRsaXN0W1sxXV1bIkdlbmVfbmFtZSJdCiAgICAgICAgdGI8LXRsaXN0W1syXV1bIkdlbmVfbmFtZSJdCiAgICAgICAgeDwtbGlzdChQV1M9cHdzJEdlbmVfbmFtZSxUQj10YiRHZW5lX25hbWUpCiAgICAgICAgZ2d2ZW5uKHgsIGZpbGxfY29sb3IgPSBjb2xzW2MoMiwxKV0sIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSh0aW1lc1tpXSkKICAgICAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVmVubl8iLHRpbWVzW2ldLCIucG5nIiksIHdpZHRoID0gMywgaGVpZ2h0PTMsIGRwaT0zMDApCiAgICB9CiAgICBpZiAoaT09Myl7CiAgICAgICAgY29tbW9uX3N1bW1hcnkkUFdTW2ldPC1ucm93KHRsaXN0W1tncmVwKCJQV1MiLCBuYW1lcyh0bGlzdCkpXV0pCiAgICAgICAgY29tbW9uX3N1bW1hcnkkVEJbaV08LSBucm93KHRsaXN0W1tncmVwKCJUQiIsIG5hbWVzKHRsaXN0KSldXSkKICAgICAgICBjb21tb25fc3VtbWFyeSRTU1tpXTwtIG5yb3codGxpc3RbW2dyZXAoIlNTIiwgbmFtZXModGxpc3QpKV1dKQogICAgICAgIAogICAgICAgIGdlbmVzMTwtaW50ZXJzZWN0KHRsaXN0W1sxXV1bIkdlbmVfbmFtZSJdLCB0bGlzdFtbM11dWyJHZW5lX25hbWUiXSkKICAgICAgICBnZW5lczI8LWludGVyc2VjdCh0bGlzdFtbMV1dWyJHZW5lX25hbWUiXSwgdGxpc3RbWzJdXVsiR2VuZV9uYW1lIl0pCiAgICAgICAgZ2VuZXMzPC1pbnRlcnNlY3QodGxpc3RbWzJdXVsiR2VuZV9uYW1lIl0sIHRsaXN0W1szXV1bIkdlbmVfbmFtZSJdKQogICAgICAgIGdlbmVzNDwtaW50ZXJzZWN0KHRsaXN0W1sxXV1bIkdlbmVfbmFtZSJdLGludGVyc2VjdCh0bGlzdFtbMl1dWyJHZW5lX25hbWUiXSwgdGxpc3RbWzNdXVsiR2VuZV9uYW1lIl0pKQogICAgICAgIGNvbW1vbl9zdW1tYXJ5JGNvbW1vbl9QV1MuVEJbaV08LW5yb3coZ2VuZXMxKQogICAgICAgIGNvbW1vbl9zdW1tYXJ5JGNvbW1vbl9QV1MuU1NbaV08LW5yb3coZ2VuZXMyKQogICAgICAgIGNvbW1vbl9zdW1tYXJ5JGNvbW1vbl9TUy5UQltpXTwtbnJvdyhnZW5lczMpCiAgICAgICAgY29tbW9uX3N1bW1hcnkkY29tbW9uM1tpXTwtbnJvdyhnZW5lczQpCiAgICAgICAgaz1pCiAgICAgICAgY29tbW9uW1trXV08LWdlbmVzMgogICAgICAgIG5hbWVzKGNvbW1vbilbW2tdXTwtcGFzdGUwKHRpbWVzW2ldLCJfUFdTLlNTIikKICAgICAgICBrPWsrMQogICAgICAgIGNvbW1vbltba11dPC1nZW5lczEKICAgICAgICBuYW1lcyhjb21tb24pW1trXV08LXBhc3RlMCh0aW1lc1tpXSwiX1BXUy5UQiIpCiAgICAgICAgaz1rKzEKICAgICAgICBjb21tb25bW2tdXTwtZ2VuZXMzCiAgICAgICAgbmFtZXMoY29tbW9uKVtba11dPC1wYXN0ZTAodGltZXNbaV0sIl9TUy5UQiIpCiAgICAgICAgaz1rKzEKICAgICAgICBjb21tb25bW2tdXTwtZ2VuZXM0CiAgICAgICAgbmFtZXMoY29tbW9uKVtba11dPC1wYXN0ZTAodGltZXNbaV0sIl8zcG9wcyIpCiAgICAgICAgCiAgICAgICAgcHdzPC10bGlzdFtbMV1dWyJHZW5lX25hbWUiXQogICAgICAgIHRiPC10bGlzdFtbM11dWyJHZW5lX25hbWUiXQogICAgICAgIHNzPC10bGlzdFtbMl1dWyJHZW5lX25hbWUiXQogICAgICAgIHg8LWxpc3QoUFdTPXB3cyRHZW5lX25hbWUsVEI9dGIkR2VuZV9uYW1lLCBTUz1zcyRHZW5lX25hbWUpCiAgICAgICAgZ2d2ZW5uKHgsIGZpbGxfY29sb3IgPSBjb2xzW2MoMiwxLDMpXSwgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKHRpbWVzW2ldKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9WZW5uXyIsdGltZXNbaV0sIi5wbmciKSwgd2lkdGggPSA0LCBoZWlnaHQ9NCwgZHBpPTMwMCkKICAgICAgICAKICAgICAgICAgeDE8LWxpc3QoUFdTPXB3cyRHZW5lX25hbWUsVEI9dGIkR2VuZV9uYW1lKQogICAgICAgIGdndmVubih4MSwgZmlsbF9jb2xvciA9IGNvbHNbYygyLDEpXSwgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKHRpbWVzW2ldKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9WZW5uX1BXU19UQl8iLHRpbWVzW2ldLCIucG5nIiksIHdpZHRoID0gMywgaGVpZ2h0PTMsIGRwaT0zMDApCiAgICAgICAgIHgyPC1saXN0KFBXUz1wd3MkR2VuZV9uYW1lLFNTPXNzJEdlbmVfbmFtZSkKICAgICAgICBnZ3Zlbm4oeDIsIGZpbGxfY29sb3IgPSBjb2xzW2MoMiwzKV0sIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSh0aW1lc1tpXSkKICAgICAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVmVubl9QV1NfU1NfIix0aW1lc1tpXSwiLnBuZyIpLCB3aWR0aCA9IDMsIGhlaWdodD0zLCBkcGk9MzAwKQogICAgICAgICAgeDM8LWxpc3QoU1M9c3MkR2VuZV9uYW1lLCBUQj10YiRHZW5lX25hbWUpCiAgICAgICAgZ2d2ZW5uKHgzLCBmaWxsX2NvbG9yID0gY29sc1tjKDMsMSldLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUodGltZXNbaV0pCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1Zlbm5fU1NfVEJfIix0aW1lc1tpXSwiLnBuZyIpLCB3aWR0aCA9IDMsIGhlaWdodD0zLCBkcGk9MzAwKQogICAgICAgIAogICAgICAgIAogICAgICAgIH0KfQp3cml0ZS5jc3YoY29tbW9uX3N1bW1hcnksICIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvQ29tbW9uX2dlbmVzX3dpdGhJbnRlcmdlbmVzXzNwb3BzLmNzdiIpCgoKI1doYXQgYXJlIHRoZSBvdmVybGFwcGluZyBnZW5lIG5hbWVzIGJldHdlZW4gcG9wdWxhdGlvbnMKY29tbW9uX3RpbWVzPC1saXN0KCkKZm9yIChpIGluIDE6IGxlbmd0aChjb21tb24pKXsKICAgIGdpZHM8LWNvbW1vbltbaV1dCiAgICBkZjwtZGF0YS5mcmFtZShHZW5lX25hbWU9Z2lkcykKICAgIAogICAgZGYyPC1tZXJnZShkZiwgR2VuZXMsIGJ5PSJHZW5lX25hbWUiKQogICAgd3JpdGUuY3N2KGRmMiwgcGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvQ29tbW9uX2dlbmVzXyIsIG5hbWVzKGNvbW1vbilbaV0sIi5jc3YiKSwgcm93Lm5hbWVzID0gRikKICAgIGNvbW1vbl90aW1lc1tbaV1dPC1kZjIKICAgIG5hbWVzKGNvbW1vbl90aW1lcylbaV08LSBuYW1lcyhjb21tb24pW2ldCn0KCgojb3ZlcmxhcHBpbmcgZ2VuZXMgQ09WMTIKCnRsaXN0PC1HZW5lTGlzdFtncmVwKHRpbWVzWzFdLCBuYW1lcyhHZW5lTGlzdCkpXQpnZW5lczE8LWludGVyc2VjdCh0bGlzdFtbMV1dWyJHZW5lX0lEIl0sIHRsaXN0W1syXV1bIkdlbmVfSUQiXSkgI2NvbW1vbiBnZW5lcyBiZXR3ZWVuIFBXUyBhbmQgVEIgaW4gY292MTIKZzE8LXVuaXF1ZShnZW5lczEkR2VuZV9JRCkKc2luaygiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL292ZXJsYXBwaW5nX2dlbmVzL2dlbmVJRHNfUFdTX1RCX2NvdjEyLnR4dCIpCmNhdChwYXN0ZTAoZzEsICI7IikpCnNpbmsoTlVMTCkKCiMgT3ZlcmxhcHBpbmcgZ2VuZXMgQ09WMTMKCnRsaXN0PC1HZW5lTGlzdFtncmVwKHRpbWVzWzJdLCBuYW1lcyhHZW5lTGlzdCkpXQpnZW5lczE8LWludGVyc2VjdCh0bGlzdFtbMV1dWyJHZW5lX0lEIl0sIHRsaXN0W1syXV1bIkdlbmVfSUQiXSkgI2NvbW1vbiBnZW5lcyBiZXR3ZWVuIFBXUyBhbmQgVEIgaW4gY292MTIKZzE8LXVuaXF1ZShnZW5lczEkR2VuZV9JRCkKc2luaygiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL292ZXJsYXBwaW5nX2dlbmVzL2dlbmVJRHNfUFdTX1RCX2NvdjEzLnR4dCIpCmNhdChwYXN0ZTAoZzEsICI7IikpCnNpbmsoTlVMTCkKCgoKCiNvdmVybGFwcGluZyBnZW5lcyBDT1YyMwoKdGxpc3Q8LUdlbmVMaXN0W2dyZXAodGltZXNbM10sIG5hbWVzKEdlbmVMaXN0KSldCnB3czIzPC10bGlzdFtbMV1dWyJHZW5lX0lEIl0Kc3MyMzwtdGxpc3RbWzJdXVsiR2VuZV9JRCJdCnRiMjM8LXRsaXN0W1szXV1bIkdlbmVfSUQiXQpnZW5lczE8LWludGVyc2VjdCh0bGlzdFtbMV1dWyJHZW5lX0lEIl0sIHRsaXN0W1szXV1bIkdlbmVfSUQiXSkgI2NvbW1vbiBnZW5lcyBiZXR3ZWVuIFBXUyBhbmQgVEIgaW4gY292MjMKZ2VuZXMyPC1pbnRlcnNlY3QodGxpc3RbWzFdXVsiR2VuZV9JRCJdLCB0bGlzdFtbMl1dWyJHZW5lX0lEIl0pICNjb21tb24gZ2VuZXMgYmV0d2VlbiBQV1MgYW5kIFNTIGluIGNvdjIzCmdlbmVzMzwtaW50ZXJzZWN0KHRsaXN0W1syXV1bIkdlbmVfSUQiXSwgdGxpc3RbWzNdXVsiR2VuZV9JRCJdKSAjY29tbW9uIGdlbmVzIGJldHdlZW4gU1MgYW5kIFRCIGluIGNvdjIzCmdlbmVzNDwtaW50ZXJzZWN0KHRsaXN0W1sxXV1bIkdlbmVfSUQiXSxpbnRlcnNlY3QodGxpc3RbWzJdXVsiR2VuZV9JRCJdLCB0bGlzdFtbM11dWyJHZW5lX0lEIl0pKSAjIENvbW1vbiBnZW5lcyBpbiBhbGwgMyBwb3B1bGF0aW9ucwpnMTwtdW5pcXVlKGdlbmVzMSRHZW5lX0lEKQpzaW5rKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvb3ZlcmxhcHBpbmdfZ2VuZXMvZ2VuZUlEc19QV1NfVEJfY292MjMudHh0IikKY2F0KHBhc3RlMChnMSwgIjsiKSkKc2luayhOVUxMKQoKZzI8LXVuaXF1ZShnZW5lczIkR2VuZV9JRCkKc2luaygiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL292ZXJsYXBwaW5nX2dlbmVzL2dlbmVJRHNfUFdTX1NTX2NvdjIzLnR4dCIpCmNhdChwYXN0ZTAoZzIsICI7IikpCnNpbmsoTlVMTCkKCmczPC11bmlxdWUoZ2VuZXMzJEdlbmVfSUQpCnNpbmsoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9vdmVybGFwcGluZ19nZW5lcy9nZW5lSURzX1NTX1RCX2NvdjIzLnR4dCIpCmNhdChwYXN0ZTAoZzMsICI7IikpCnNpbmsoTlVMTCkKCmc0PC11bmlxdWUoZ2VuZXM0JEdlbmVfSUQpCnNpbmsoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9vdmVybGFwcGluZ19nZW5lcy9nZW5lSURzX2FsbDNfY292MjMudHh0IikKY2F0KHBhc3RlMChnNCwgIjsiKSkKc2luayhOVUxMKQoKCgojMi4gQmV0d2VlbiBUaW1lLVBvaW50cyB3aXRoaW4gYSBwb3B1bGF0aW9uCgp0aW1lczwtYygiY292MTIiLCJjb3YxMyIsImNvdjIzIikKcG9wczwtYygiUFdTIiwiVEIiKQpjb21tb24yPC1saXN0KCkKY29tbW9uX3N1bW1hcnkyPC1kYXRhLmZyYW1lKHBvcD1yZXAocG9wc1sxOjJdLCBlYWNoPTQpKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgcGxpc3Q8LUdlbmVMaXN0W2dyZXAocG9wc1tpXSwgbmFtZXMoR2VuZUxpc3QpKV0KICAgIGs9NCppLTMKICAgICNjb21tb24gZ2VuZXMgYmV0d2VlbiBDT1YxMiBhbmQgQ09WMTMKICAgIGNvbW1vbl9nZW5lczE8LWludGVyc2VjdChwbGlzdFtbMV1dWyJHZW5lX25hbWUiXSwgcGxpc3RbWzJdXVsiR2VuZV9uYW1lIl0pCiAgICBjb21tb24yW1trXV08LWNvbW1vbl9nZW5lczEKICAgIG5hbWVzKGNvbW1vbjIpW1trXV08LXBhc3RlMChwb3BzW2ldLCIuIiwgdGltZXNbMV0sIl8iLHRpbWVzWzJdKQogICAgY29tbW9uX3N1bW1hcnkyJFRpbWVba108LXBhc3RlMCh0aW1lc1sxXSwiXyIsdGltZXNbMl0pCiAgICBjb21tb25fc3VtbWFyeTIkbm8ub2YuZ2VuZXNba108LW5yb3coY29tbW9uX2dlbmVzMSkgCiAgICAKICAgIGMxMjwtcGxpc3RbWzFdXVsiR2VuZV9uYW1lIl0KICAgIGMxMzwtcGxpc3RbWzJdXVsiR2VuZV9uYW1lIl0KICAgIGMyMzwtcGxpc3RbWzNdXVsiR2VuZV9uYW1lIl0KICAgIHg8LWxpc3QoQ09WMTI9YzEyJEdlbmVfbmFtZSxDT1YxMz1jMTMkR2VuZV9uYW1lLCBDT1YyMz1jMjMkR2VuZV9uYW1lKQogICAgZ2d2ZW5uKHgsIGZpbGxfY29sb3IgPSBjb2xzW2MoMSw1LDcpXSwgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVmVubl8iLHBvcHNbaV0sIi5wbmciKSwgd2lkdGggPSA0LCBoZWlnaHQ9NCwgZHBpPTMwMCkKCiAgICAKICAgIGs9aysxCiAgICAjY29tbW9uIGdlbmVzIGJldHdlZW4gQ09WMTIgYW5kIENPVjIzCiAgICBjb21tb25fZ2VuZXMyPC1pbnRlcnNlY3QocGxpc3RbWzFdXVsiR2VuZV9uYW1lIl0sIHBsaXN0W1szXV1bIkdlbmVfbmFtZSJdKQogICAgY29tbW9uMltba11dPC1jb21tb25fZ2VuZXMyCiAgICBuYW1lcyhjb21tb24yKVtba11dPC1wYXN0ZTAocG9wc1tpXSwiLiIsIHRpbWVzWzFdLCJfIix0aW1lc1szXSkKICAgIGNvbW1vbl9zdW1tYXJ5MiRUaW1lW2tdPC1wYXN0ZTAodGltZXNbMV0sIl8iLHRpbWVzWzNdKQogICAgY29tbW9uX3N1bW1hcnkyJG5vLm9mLmdlbmVzW2tdPC1ucm93KGNvbW1vbl9nZW5lczIpIAogCiAgICBrPWsrMQogICAgI2NvbW1vbiBnZW5lcyBiZXR3ZWVuIENPVjEzIGFuZCBDT1YyMwogICAgY29tbW9uX2dlbmVzMzwtaW50ZXJzZWN0KHBsaXN0W1syXV1bIkdlbmVfbmFtZSJdLCBwbGlzdFtbM11dWyJHZW5lX25hbWUiXSkKICAgIGNvbW1vbjJbW2tdXTwtY29tbW9uX2dlbmVzMwogICAgbmFtZXMoY29tbW9uMilbW2tdXTwtcGFzdGUwKHBvcHNbaV0sIi4iLCB0aW1lc1syXSwiXyIsdGltZXNbM10pCiAgICBjb21tb25fc3VtbWFyeTIkVGltZVtrXTwtcGFzdGUwKHRpbWVzWzJdLCJfIix0aW1lc1szXSkKICAgIGNvbW1vbl9zdW1tYXJ5MiRuby5vZi5nZW5lc1trXTwtbnJvdyhjb21tb25fZ2VuZXMzKSAKIAogICAgaz1rKzEKICAgICNjb21tb24gZ2VuZXMgYW1vbmcgYWxsIHRpbWUgcGVyaW9kcwogICAgY29tbW9uX2dlbmVzNDwtaW50ZXJzZWN0KHBsaXN0W1sxXV1bIkdlbmVfbmFtZSJdLCAoaW50ZXJzZWN0KHBsaXN0W1syXV1bIkdlbmVfbmFtZSJdLCBwbGlzdFtbM11dWyJHZW5lX25hbWUiXSkpKQogICAgY29tbW9uMltba11dPC1jb21tb25fZ2VuZXM0CiAgICBuYW1lcyhjb21tb24yKVtba11dPC1wYXN0ZTAocG9wc1tpXSwiLmFsbCIpCiAgICBjb21tb25fc3VtbWFyeTIkVGltZVtrXTwtIkFsbCIKICAgIGNvbW1vbl9zdW1tYXJ5MiRuby5vZi5nZW5lc1trXTwtbnJvdyhjb21tb25fZ2VuZXM0KSAKfQp3cml0ZS5jc3YoY29tbW9uX3N1bW1hcnkyLCAiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0NvbW1vbl9nZW5lc19iZXR3ZWVuVGltZVBvaW50cy5jc3YiKQoKCiNDb21tb24gZ2VuZSBuYW1lcyBiZXR3ZWVuIHRpbWUgcG9pbnRzCgpmb3IgKGkgaW4gMToyKXsKICAgIENvbW1vbkdlbmVzPC1kYXRhLmZyYW1lKCkKICAgIGdsaXN0PC1jb21tb24yW2dyZXAocG9wc1tpXSwgbmFtZXMoY29tbW9uMikpXQogICAgZm9yKGogaW4gMTpsZW5ndGgoZ2xpc3QpKXsKICAgICAgICBnaWRzPC1nbGlzdFtbal1dCiAgICAgICAgZGY8LWRhdGEuZnJhbWUoR2VuZV9uYW1lPWdpZHMpCiAgICAgICAgZGYyPC1tZXJnZShkZiwgR2VuZXMsIGJ5PSJHZW5lX25hbWUiLCBhbGwueD1UKQogICAgICAgIHdyaXRlLmNzdihkZjIsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0NvbW1vbl9nZW5lc18iLCBuYW1lcyhnbGlzdClbal0sIi5jc3YiKSwgcm93Lm5hbWVzID0gRikKICAgICAgICBkZjIkVGltZTwtbmFtZXMoZ2xpc3QpW2pdCiAgICAgICAgQ29tbW9uR2VuZXM8LXJiaW5kKENvbW1vbkdlbmVzLCBkZjIpCiAgICB9CiAgICB3cml0ZS5jc3YoQ29tbW9uR2VuZXMsIHBhc3RlMCgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0NvbW1vbl9nZW5lc18iLHBvcHNbaV0gLCIuY3N2IiksIHJvdy5uYW1lcyA9IEYpCn0KCgoKYGBgCgoKCiMjIyMgT3ZlcmxhcHBpbmcgZ2VuZSBudW1iZXJzICAgCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMgU3VtbWFyeSB0YWJsZQpjb21tb25fZ2VuZXM8LXJlYWQuY3N2KCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvQ29tbW9uX2dlbmVzX3dpdGhJbnRlcmdlbmVzXzNwb3BzLmNzdiIsIHJvdy5uYW1lcyA9IDEpCmtuaXRyOjprYWJsZShjb21tb25fZ2VuZXMpCgpgYGAKCgojIyBXaGF0IGFyZSB0aGUgZ2VuZXMgb3ZlcmxhcHBpbmcgYWNyb3NzIGRpZmZlcmVudCB0aW1lIHBvaW50cyBiZXR3ZWVuIHBvcHVsYXRpb25zPyAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIEJldHdlZW4gUFdTIGFuZCBUQgpwd3MudGI8LWNvbW1vbl90aW1lc1tjKDEsMiw0KV0KCiMgMS4gQ29tbW9uIGdlbmVzIGJldHdlZW4gcG9wdWxhdGlvbnMgYWNyb3NzIHRpbWUgcG9pbnRzIGluIFBXUyBhbmQgVEIgKENPVjEyIC0gQ09WMTMpCmdlbmVzMTIxMzwtaW50ZXJzZWN0KHB3cy50YltbMV1dWyJHZW5lX25hbWUiXSwgcHdzLnRiW1syXV1bIkdlbmVfbmFtZSJdKQpnZW5lczEyMTM8LW1lcmdlKGdlbmVzMTIxMywgR2VuZXMsIGJ5PSJHZW5lX25hbWUiKQp3cml0ZS5jc3YoZ2VuZXMxMjEzLCAiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0NvbW1vbl9nZW5lc19QV1MuVEIuY292MTItY292MjMuY3N2IikKIyAgICAgICAgICAgR2VuZV9uYW1lICAgY2hyICAgICAgICAgICAgR2VuZV9JRAojMSBFTlNDSEFHMDAwMDAwMDE2ODcgY2hyMTMgRU5TQ0hBRzAwMDAwMDAxNjg3CiMyICAgICAgICAgICAgIG5kc3QyYSBjaHIxMyBFTlNDSEFHMDAwMDAwMDI2NDkKIzMgICAgICAgICAgICAgenN3aW04IGNocjEzIEVOU0NIQUcwMDAwMDAwNTk1NgoKI2NvbW1vbiBnZW5lIG5hbWVzCnAxMjEzPC1wd3MudGJbWzFdXVsiR2VuZV9uYW1lIl0KdDEyMTM8LXB3cy50YltbMl1dWyJHZW5lX25hbWUiXQp4PC1saXN0KFBXUz1wMTIxMyRHZW5lX25hbWUsVEI9dDEyMTMkR2VuZV9uYW1lKQpnZ3Zlbm4oeCwgZmlsbF9jb2xvciA9IGNvbHNbYygyLDEpXSwgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJDT1YxMi1DT1YxMyBpbiBQV1MgJiBUQiIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL1Zlbm5fUFdTX1RCX0NPVjEyLUNPVjEzLnBuZyIpLCB3aWR0aCA9IDMsIGhlaWdodD0zLCBkcGk9MzAwKQogICAgICAgIAoKIyAyLiBDb21tb24gZ2VuZXMgYmV0d2VlbiBwb3B1bGF0aW9ucyBhY3Jvc3MgdGltZSBwb2ludHMgaW4gUFdTIGFuZCBUQiAoQ09WMTIgLSBDT1YyMykKCmdlbmVzMTIyMzwtaW50ZXJzZWN0KHB3cy50YltbMV1dWyJHZW5lX25hbWUiXSwgcHdzLnRiW1szXV1bIkdlbmVfbmFtZSJdKQpnZW5lczEyMjM8LW1lcmdlKGdlbmVzMTIyMywgR2VuZXMsIGJ5PSJHZW5lX25hbWUiKQp3cml0ZS5jc3YoZ2VuZXMxMjIzLCAiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL0NvbW1vbl9nZW5lc19QV1MuVEIuY292MTItY292MTMuY3N2IikKIyAgICAgICAgICAgR2VuZV9uYW1lICAgY2hyICAgICAgICAgICAgR2VuZV9JRAojMSBFTlNDSEFHMDAwMDAwMDE2ODcgY2hyMTMgRU5TQ0hBRzAwMDAwMDAxNjg3CiMyIEVOU0NIQUcwMDAwMDAyMjcwOSBjaHIyMCBFTlNDSEFHMDAwMDAwMjI3MDkKIzMgRU5TQ0hBRzAwMDAwMDIyODE1IGNocjIwIEVOU0NIQUcwMDAwMDAyMjgxNQojNCAgICAgICAgICAgICBuZHN0MmEgY2hyMTMgRU5TQ0hBRzAwMDAwMDAyNjQ5CgpwMTIyMzwtcHdzLnRiW1sxXV1bIkdlbmVfbmFtZSJdCnQxMjIzPC1wd3MudGJbWzNdXVsiR2VuZV9uYW1lIl0KeDwtbGlzdChQV1M9cDEyMjMkR2VuZV9uYW1lLFRCPXQxMjIzJEdlbmVfbmFtZSkKZ2d2ZW5uKHgsIGZpbGxfY29sb3IgPSBjb2xzW2MoMiwxKV0sIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiQ09WMTItQ09WMjMgaW4gUFdTICYgVEIiKQpnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVmVubl9QV1NfVEJfQ09WMTItQ09WMjMucG5nIiksIHdpZHRoID0gMywgaGVpZ2h0PTMsIGRwaT0zMDApCgoKIyAzLiBiZXR3ZWVuIFBXUyBhbmQgVEIgYWNyb3NzIENPVjEzIGFuZCBDT1YyMwpnZW5lczEzMjM8LWludGVyc2VjdChwd3MudGJbWzJdXVsiR2VuZV9uYW1lIl0sIHB3cy50YltbM11dWyJHZW5lX25hbWUiXSkKZ2VuZXMxMzIzPC1tZXJnZShnZW5lczEzMjMsIEdlbmVzLCBieT0iR2VuZV9uYW1lIikKd3JpdGUuY3N2KGdlbmVzMTMyMywgIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9vbW1vbl9nZW5lc19QV1MuVEIuY292MTMtY292MjMuY3N2IikKIyAgICAgICAgICAgR2VuZV9uYW1lICAgY2hyICAgICAgICAgICAgR2VuZV9JRAojMSBFTlNDSEFHMDAwMDAwMDE2ODcgY2hyMTMgRU5TQ0hBRzAwMDAwMDAxNjg3CiMyICAgICAgICAgICAgIG5kc3QyYSBjaHIxMyBFTlNDSEFHMDAwMDAwMDI2NDkKCnAxMzIzPC1wd3MudGJbWzJdXVsiR2VuZV9uYW1lIl0KdDEzMjM8LXB3cy50YltbM11dWyJHZW5lX25hbWUiXQp4PC1saXN0KFBXUz1wMTMyMyRHZW5lX25hbWUsVEI9dDEzMjMkR2VuZV9uYW1lKQpnZ3Zlbm4oeCwgZmlsbF9jb2xvciA9IGNvbHNbYygyLDEpXSwgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJDT1YxMy1DT1YyMyBpbiBQV1MgJiBUQiIpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1Zlbm5fUFdTX1RCX0NPVjEzLUNPVjIzLnBuZyIsIHdpZHRoID0gMywgaGVpZ2h0PTMsIGRwaT0zMDApCgoKCgpgYGAKCiogTnVtYmVycyBvZiBvdmVybGFwcGluZyBnZW5lcyBiZXR3ZWVuIHBvcHVsYXRpb25zIGJldHdlZW4gdGltZSBwb2ludHMgIAohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1Zlbm5fUFdTX1RCX0NPVjEyLUNPVjIzLnBuZykKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvVmVubl9QV1NfVEJfQ09WMTMtQ09WMjMucG5nKQoKCgoKIyBJbnRlcnBvcHVsYXRpb24gY29tcGFyaXNvbiBwZXIgdGltZSBwZXJpb2QgCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIyBJbnRlcnBvcHVsYXRpb24gY29tcGFyaXNvbnMKI2RlY29kZSB0aGUgc2FtcGxlcyB0byBjcmVhdGUgdGhlIHJpZ2h0IG1hdHJpeApjdjwtcmVhZC5jc3YoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC9HV19Db3ZzX2ludGVyUG9wdWxhdGlvbnNfMTAwa18zcG9wcy5jc3YiLCBoZWFkZXIgPSBGKQpsYWJzPC1yZWFkLmNzdigifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvTUQ3MDAwL0dXX0NvdnNfaW50ZXJQb3B1bGF0aW9uc18xMDBrX2xhYmVsc18zcG9wcy5jc3YiICkKbGFiczwtbGFic1ssLTFdCmN2bTwtZGF0YS5mcmFtZShsYWJlbD1hcy52ZWN0b3IodChsYWJzKSksIGNvdj1hcy52ZWN0b3IodChjdikpKQoKI3JlYXJyYW5nZSBiYXNlZCBvbiBjb21wYXJpb25zOiBjb3ZhcmlhbmNlIGJldHdlZW4gcG9wdWxhdGlvbnMgd2l0aGluIHRoZSBzYW1lIHBlcmlvZAojUG9wWXIgU3ltYm9scwojIFBIIDEgJ1BXUycsIDE5OTEKIyBQSCAyICdQV1MnLCAxOTk2CiMgUEggMyAnUFdTJywgMjAwNgojIFBIIDQgJ1BXUycsIDIwMTcKIyBQSCA1ICdTUycsICAxOTkxCiMgUEggNiAnU1MnLCAgMTk5NgojIFBIIDcgJ1NTJywgIDIwMDYKIyBQSCA4ICdTUycsICAyMDE3CiMgUEggOSAnVEInLCAgMTk5MQojIFBIIDEwJ1RCJywgIDE5OTYKIyBQSCAxMSdUQicsICAyMDA2CiMgUEggMTInVEInLCAgMjAxNwoKQ292czwtZGF0YS5mcmFtZShwb3BzPXJlcChjKCJQV1MudnMuU1MiLCAiUFdTLnZzLlRCIiwgICJTUy52cy5UQiIpLCB0aW1lcz02KSwKICAgICAgICAgICAgICAgICBwZXJpb2Q9YyhyZXAoIjE5OTEtMTk5NiIsIHRpbWVzPTMpLHJlcCgiMTk5Ni0yMDA2IiwgdGltZXM9MyksIHJlcCgiMjAwNi0yMDE3IiwgdGltZXM9MykpKQoKQ292cyRjb3Y8LWMoTkEsIGN2bSRjb3ZbY3ZtJGxhYmVsPT0iY292KFBIOiAyLTEsIFBIOiAxMC05KSJdLE5BLAogICAgICAgICAgICBjdm0kY292W2N2bSRsYWJlbD09ImNvdihQSDogMy0yLCBQSDogNy02KSJdLGN2bSRjb3ZbY3ZtJGxhYmVsPT0iY292KFBIOiAzLTIsIFBIOiAxMS0xMCkiXSwgCiAgICAgICAgICAgIGN2bSRjb3ZbY3ZtJGxhYmVsPT0iY292KFBIOiA3LTYsIFBIOiAxMS0xMCkiXSwKICAgICAgICAgICAgY3ZtJGNvdltjdm0kbGFiZWw9PSJjb3YoUEg6IDQtMywgUEg6IDgtNykiXSxjdm0kY292W2N2bSRsYWJlbD09ImNvdihQSDogNC0zLCBQSDogMTItMTEpIl0sY3ZtJGNvdltjdm0kbGFiZWw9PSJjb3YoUEg6IDgtNywgUEg6IDEyLTExKSJdKQoKCgojQy5JLgpjaXM8LXJlYWQuY3N2KCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvR1dfQ09WX0ludGVycG9wX2NvbXBhcmlzb25fQ0lzLmNzdiIpCmNpczwtY2lzWywtMV0KY2ltPC1kYXRhLmZyYW1lKGxhYmVsPWFzLnZlY3Rvcih0KGxhYnMpKSwgY2lfbD1hcy52ZWN0b3IodChjaXNbMToxMSxdKSkpCmNpbSRjaV9oPC1hcy52ZWN0b3IodChjaXNbMTI6MjIsXSkpCgpDb3ZzJGNpX2w8LWFzLm51bWVyaWMoYyhOQSxjaW0kY2lfbFtjaW0kbGFiZWw9PSJjb3YoUEg6IDItMSwgUEg6IDEwLTkpIl0sTkEsCiAgICAgICAgICAgICAgICAgICAgICBjaW0kY2lfbFtjaW0kbGFiZWw9PSJjb3YoUEg6IDMtMiwgUEg6IDctNikiXSxjaW0kY2lfbFtjaW0kbGFiZWw9PSJjb3YoUEg6IDMtMiwgUEg6IDExLTEwKSJdLCBjaW0kY2lfbFtjaW0kbGFiZWw9PSJjb3YoUEg6IDctNiwgUEg6IDExLTEwKSJdLAogICAgICAgICAgICAgICAgICAgICAgY2ltJGNpX2xbY2ltJGxhYmVsPT0iY292KFBIOiA0LTMsIFBIOiA4LTcpIl0sY2ltJGNpX2xbY2ltJGxhYmVsPT0iY292KFBIOiA0LTMsIFBIOiAxMi0xMSkiXSwgY2ltJGNpX2xbY2ltJGxhYmVsPT0iY292KFBIOiA4LTcsIFBIOiAxMi0xMSkiXSkpCgpDb3ZzJGNpX2g8LWFzLm51bWVyaWMoYyhOQSwgY2ltJGNpX2hbY2ltJGxhYmVsPT0iY292KFBIOiAyLTEsIFBIOiAxMC05KSJdLE5BLAogICAgICAgICAgICAgICAgICAgICAgY2ltJGNpX2hbY2ltJGxhYmVsPT0iY292KFBIOiAzLTIsIFBIOiA3LTYpIl0sY2ltJGNpX2hbY2ltJGxhYmVsPT0iY292KFBIOiAzLTIsIFBIOiAxMS0xMCkiXSwgY2ltJGNpX2hbY2ltJGxhYmVsPT0iY292KFBIOiA3LTYsIFBIOiAxMS0xMCkiXSwKICAgICAgICAgICAgICAgICAgICAgIGNpbSRjaV9oW2NpbSRsYWJlbD09ImNvdihQSDogNC0zLCBQSDogOC03KSJdLGNpbSRjaV9oW2NpbSRsYWJlbD09ImNvdihQSDogNC0zLCBQSDogMTItMTEpIl0sIGNpbSRjaV9oW2NpbSRsYWJlbD09ImNvdihQSDogOC03LCBQSDogMTItMTEpIl0pKQoKCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpkaXNwbGF5LmJyZXdlci5hbGwodHlwZT0icXVhbCIpCgpjb2xvcnMyPC1icmV3ZXIucGFsKG49OCwgIlNldDMiKQoiIzhERDNDNyIgIiNGRkZGQjMiICIjQkVCQURBIiAiI0ZCODA3MiIgIiM4MEIxRDMiICIjRkRCNDYyIiAiI0IzREU2OSIgIiNGQ0NERTUiCgojQmFycGxvdApnZ3Bsb3QoQ292cywgYWVzKHg9cGVyaW9kLCB5PWNvdiwgZmlsbD1wb3BzKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcpLCB3aWR0aD0wLjgpKwogICAgeWxhYigiQ292YXJpYW5jZSIpK3hsYWIoJycpK3RoZW1lX2NsYXNzaWMoKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsY29sb3I9ImdyYXk3MCIsIHNpemU9MC4zKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jb2xvcnMyW2MoNCwxLDMpXSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSsKICAgIHlsaW0oLTAuMDAxMywgMC4wMDIpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygxLjUsMi41KSwgY29sb3I9ImdyYXkiLCBzaXplPTAuMikrCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPWNpX2wsIHltYXg9Y2lfaCksIHdpZHRoPS4yLCBzaXplPS4yLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNykpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9JbnRlcnBvcF9jb3ZfY29tcGFyaXNvbl8zUG9wc19uZXcucG5nIix3aWR0aCA9IDQuOCwgaGVpZ2h0ID0gMywgZHBpPTMwMCkKCiNQb2ludCBwbG90CmdncGxvdChDb3ZzLCBhZXMoeD1wZXJpb2QsIHk9Y292LCBjb2xvcj1wb3BzKSkrCiAgICBnZW9tX3BvaW50KHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43KSwgc2l6ZT0zKSsKICAgIHlsYWIoIkNvdmFyaWFuY2UiKSt4bGFiKCcnKSt0aGVtZV9jbGFzc2ljKCkrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLGNvbG9yPSJncmF5NzAiLCBzaXplPTAuMykrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbG9yczJbYyg0LDEsMyldKSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1jaV9sLCB5bWF4PWNpX2gpLCB3aWR0aD0uMiwgc2l6ZT0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcpKSsKICAgIHlsaW0oLTAuMDAyMywgMC4wMDIpKwogICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSksIGNvbG9yPSJncmF5Iiwgc2l6ZT0wLjMpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9JbnRlcnBvcF9jb3ZfY29tcGFyaXNvbl8zUG9wc19uZXdfUG9pbnRQbG90LnBuZyIsd2lkdGggPSA0LjgsIGhlaWdodCA9IDMsIGRwaT0zMDApCgoKCiNsaW5lIHBsb3QKQ292cyR0aW1lPC0xCkNvdnMkdGltZVtDb3ZzJHBlcmlvZD09IjE5OTYtMjAwNiJdPC0yCkNvdnMkdGltZVtDb3ZzJHBlcmlvZD09IjIwMDYtMjAxNyJdPC0zCkNvdnM8LUNvdnNbb3JkZXIoQ292cyR0aW1lKSxdCmdncGxvdChDb3ZzLCBhZXMoeD10aW1lLCB5PWNvdiwgY29sb3I9cG9wcywgZ3JvdXA9cG9wcykpKwogICAgZ2VvbV9wb2ludChwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNyksIHNpemU9NCkrCiAgICBnZW9tX3BhdGgocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcpKSsKICAgIHlsYWIoIkNvdmFyaWFuY2UiKSt4bGFiKCcnKSt0aGVtZV9jbGFzc2ljKCkrCiAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLGNvbG9yPSJncmF5NzAiLCBzaXplPTAuMykrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbG9yczJbYyg0LDEsMyldKSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpKwogICAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1jaV9sLCB5bWF4PWNpX2gpLCB3aWR0aD0uMiwgc2l6ZT0uMiwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcpKSsKICAgIHlsaW0oLTAuMDAyMywgMC4wMDIpKwogICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSksIGNvbG9yPSJncmF5Iiwgc2l6ZT0wLjIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzID0gYygiMTk5MS0xOTk2IiwiMTk5Ni0yMDA2IiwiMjAwNi0yMDE3IikpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9JbnRlcnBvcF9jb3ZfY29tcGFyaXNvbl8zUG9wc19uZXdfTGluZVBsb3QucG5nIix3aWR0aCA9IDQuOCwgaGVpZ2h0ID0gMywgZHBpPTMwMCkKCmBgYAoKIVtdKC4uL091dHB1dC9DT1YvSW50ZXJwb3BfY292X2NvbXBhcmlzb25fM1BvcHNfbmV3LnBuZykKCgohW10oLi4vT3V0cHV0L0NPVi9JbnRlcnBvcF9jb3ZfY29tcGFyaXNvbl8zUG9wc19uZXdfTGluZVBsb3QucG5nKQoKIyMgTG9uZ2VyIHRpbWUgcGVyaW9kICAKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgTG9uZ2VyIHRpbWUtcGVyaW9kCkNvdnMyPC1kYXRhLmZyYW1lKHBvcHM9cmVwKGMoIlBXUy52cy5TUyIsICJQV1MudnMuVEIiLCAgIlNTLnZzLlRCIiksIHRpbWVzPTMpLAogICAgICAgICAgICAgICAgIHBlcmlvZD1jKHJlcCgiMTk5MS0yMDA2IiwgdGltZXM9MykscmVwKCIxOTkxLTIwMTciLCB0aW1lcz0zKSxyZXAoIjE5OTYtMjAxNyIsIHRpbWVzPTMpKSkKCmN2MTwtcmVhZC5jc3YoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC9HV19Db3ZzX2ludGVyUG9wdWxhdGlvbnNfMTAwa18xOTkxLTIwMDYuY3N2IiwgaGVhZGVyID0gRikKbGFiczE8LXJlYWQuY3N2KCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvR1dfQ292c19pbnRlclBvcHVsYXRpb25zXzEwMGtfbGFiZWxzXzE5OTEtMjAwNi5jc3YiICkKbGFiczE8LWxhYnMxWywtMV0KY3ZtMTwtZGF0YS5mcmFtZShsYWJlbD1hcy52ZWN0b3IodChsYWJzMSkpLCBjb3Y9YXMudmVjdG9yKHQoY3YxKSkpCgpjdjI8LXJlYWQuY3N2KCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvR1dfQ292c19pbnRlclBvcHVsYXRpb25zXzEwMGtfMTk5MS0yMDE3LmNzdiIsIGhlYWRlciA9IEYpCmxhYnMyPC1yZWFkLmNzdigifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvTUQ3MDAwL0dXX0NvdnNfaW50ZXJQb3B1bGF0aW9uc18xMDBrX2xhYmVsc18xOTkxLTIwMTcuY3N2IiApCmxhYnMyPC1sYWJzMlssLTFdCmN2bTI8LWRhdGEuZnJhbWUobGFiZWw9YXMudmVjdG9yKHQobGFiczIpKSwgY292PWFzLnZlY3Rvcih0KGN2MikpKQoKY3YzPC1yZWFkLmNzdigifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvTUQ3MDAwL0dXX0NvdnNfaW50ZXJQb3B1bGF0aW9uc18xMDBrXzE5OTYtMjAxNy5jc3YiLCBoZWFkZXIgPSBGKQpsYWJzMzwtcmVhZC5jc3YoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC9HV19Db3ZzX2ludGVyUG9wdWxhdGlvbnNfMTAwa19sYWJlbHNfMTk5Ni0yMDE3LmNzdiIgKQpsYWJzMzwtbGFiczNbLC0xXQpjdm0zPC1kYXRhLmZyYW1lKGxhYmVsPWFzLnZlY3Rvcih0KGxhYnMzKSksIGNvdj1hcy52ZWN0b3IodChjdjMpKSkKCkNvdnMyJGNvdjwtYyhOQSwgY3ZtMSRjb3ZbY3ZtMSRsYWJlbD09ImNvdihQSDogMi0xLCBQSDogNC0zKSJdLCBOQSwKICAgICAgICAgICAgIE5BLCBjdm0yJGNvdltjdm0yJGxhYmVsPT0iY292KFBIOiAyLTEsIFBIOiA0LTMpIl0sIE5BLAogICAgICAgICAgICAgY3ZtMyRjb3ZbY3ZtMyRsYWJlbD09ImNvdihQSDogMi0xLCBQSDogNC0zKSJdLCBjdm0zJGNvdltjdm0zJGxhYmVsPT0iY292KFBIOiAyLTEsIFBIOiA2LTUpIl0sIGN2bTMkY292W2N2bTMkbGFiZWw9PSJjb3YoUEg6IDQtMywgUEg6IDYtNSkiXSkKCiNDLkkuCmNpczE8LXJlYWQuY3N2KCJ+L1Byb2plY3RzL1BhY2hlcnJpbmdfVmluY2VudC9NRDcwMDAvR1dfQ09WX0ludGVycG9wX2NvbXBhcmlzb25fQ0lzXzE5OTEtMjAwNi5jc3YiKQpjaXMxPC1jaXMxWywtMV0KY2lzMjwtcmVhZC5jc3YoIn4vUHJvamVjdHMvUGFjaGVycmluZ19WaW5jZW50L01ENzAwMC9HV19DT1ZfSW50ZXJwb3BfY29tcGFyaXNvbl9DSXNfMTk5MS0yMDE3LmNzdiIpCmNpczI8LWNpczJbLC0xXQpjaXMzPC1yZWFkLmNzdigifi9Qcm9qZWN0cy9QYWNoZXJyaW5nX1ZpbmNlbnQvTUQ3MDAwL0dXX0NPVl9JbnRlcnBvcF9jb21wYXJpc29uX0NJc18xOTk2LTIwMTcuY3N2IikKY2lzMzwtY2lzM1ssLTFdCgojY2ltPC1kYXRhLmZyYW1lKGxhYmVsPWFzLnZlY3Rvcih0KGxhYnMpKSwgY2lfbD1hcy52ZWN0b3IodChjaXMxWzE6NCxdKSkpCiNjaW0kY2lfaDwtYXMudmVjdG9yKHQoY2lzWzEyOjIyLF0pKQoKQ292czIkY2lfbDwtYXMubnVtZXJpYyhjKE5BLGNpczFbMSwzXSxOQSwKICAgICAgICAgICAgICAgICAgICAgICAgTkEsY2lzMlsxLDNdLE5BLAogICAgICAgICAgICAgICAgICAgICAgY2lzM1sxLDNdLGNpczNbMSw1XSxjaXMzWzMsNV0pKQoKQ292czIkY2lfaDwtYXMubnVtZXJpYyhjKE5BLGNpczFbNCwzXSxOQSwKICAgICAgICAgICAgICAgICAgICAgICAgTkEsY2lzMls0LDNdLE5BLAogICAgICAgICAgICAgICAgICAgICAgY2lzM1s2LDNdLGNpczNbNiw1XSxjaXMzWzgsNV0pKQoKCmdncGxvdChDb3ZzMiwgYWVzKHg9cGVyaW9kLCB5PWNvdiwgZmlsbD1wb3BzKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjcpLCB3aWR0aD0wLjgpKwogICAgeWxhYigiQ292YXJpYW5jZSIpK3hsYWIoJycpK3RoZW1lX2NsYXNzaWMoKSsKICAgIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsY29sb3I9ImdyYXk3MCIsIHNpemU9MC4zKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jb2xvcnMyW2MoNCwxLDMpXSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpK3NjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkrCiAgICB5bGltKC0wLjAwMTMsIDAuMDAyKStnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDEuNSwyLjUpLCBjb2xvcj0iZ3JheSIsIHNpemU9MC4yKSsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49Y2lfbCwgeW1heD1jaV9oKSwgd2lkdGg9LjIsIHNpemU9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43KSkKZ2dzYXZlKCIuLi9PdXRwdXQvQ09WL0ludGVycG9wX2Nvdl9jb21wYXJpc29uXzNQb3BzX0xvbm9nZXJQZXJpb2QucG5nIix3aWR0aCA9IDQuOSwgaGVpZ2h0ID0gMywgZHBpPTMwMCkKCmdncGxvdChDb3ZzMiwgYWVzKHg9cGVyaW9kLCB5PWNvdiwgY29sb3I9cG9wcykpKwogICAgZ2VvbV9wb2ludChwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNyksIHNpemU9NCkrCiAgICB5bGFiKCJDb3ZhcmlhbmNlIikreGxhYignJykrdGhlbWVfY2xhc3NpYygpKwogICAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCxjb2xvcj0iZ3JheTcwIiwgc2l6ZT0wLjMpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xvcnMyW2MoNCwxLDMpXSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSsKICAgICB5bGltKC0wLjAwMTMsIDAuMDAyKSsKICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW49Y2lfbCwgeW1heD1jaV9oKSwgd2lkdGg9LjIsIHNpemU9LjIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43KSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDEuNSwyLjUpLCBjb2xvcj0iZ3JheSIsIHNpemU9MC4zKQpnZ3NhdmUoIi4uL091dHB1dC9DT1YvSW50ZXJwb3BfY292X2NvbXBhcmlzb25fM1BvcHNMb25vZ2VyUGVyaW9kX1BvaW50UGxvdC5wbmciLHdpZHRoID0gNC43LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQoKCmBgYAohW10oLi4vT3V0cHV0L0NPVi9JbnRlcnBvcF9jb3ZfY29tcGFyaXNvbl8zUG9wc0xvbm9nZXJQZXJpb2RfUG9pbnRQbG90LnBuZykKCiMgRm9jdXNlZCBmcmVxIGFuYWx5c2lzCgojIyBjY3I2YSAoY2hyMTU6IDE2LDA2Niw1MDIgLSAxNiwwOTEsNjM5KQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCnlyPC1jKDE5OTEsMTk5NiwyMDA3LDIwMTcpCm1hZjwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOjQpewogICAgYWY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvQUYvIixwb3BzW2ldLCIubWFmcyIpLHNlcD0iXHQiLCBoZWFkZXIgPSBUKQogICAgYWY8LWFmW2FmJGNocm9tbz09ImNocjE1IiZhZiRwb3NpdGlvbj49MTYwNTAwMDAmYWYkcG9zaXRpb248PTE2MTAwMDAwLF0KICAgIGFmJHllYXI8LXlyW2ldCiAgICBtYWY8LXJiaW5kKG1hZixhZikKfQp3cml0ZS5jc3YobWFmLCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvY2NyYzZfTUFGY2hhbmdlX2NocjE1XzE2TWIuY3N2IikKCnBvc2l0aW9uczwtdW5pcXVlKG1hZiRwb3NpdGlvbikKZm9yIChpIGluIDE6bGVuZ3RoKHBvc2l0aW9ucykpewogICAgZGY8LW1hZlttYWYkcG9zaXRpb249PXBvc2l0aW9uc1tpXSxdCiAgICAjQUYgYm90aCBkZWNyZWFzZWQKICAgIGlmIChkZiRrbm93bkVNW2RmJHllYXI9PTE5OTFdPmRmJGtub3duRU1bZGYkeWVhcj09MTk5Nl0gJiBkZiRrbm93bkVNW2RmJHllYXI9PTE5OTZdPmRmJGtub3duRU1bZGYkeWVhcj09MjAwN10pewogICAgICAgIG1hZiR0cmVuZFttYWYkcG9zaXRpb249PXBvc2l0aW9uc1tpXV08LSJkb3duIgogICAgfQogICAgZWxzZSBpZiAoZGYka25vd25FTVtkZiR5ZWFyPT0xOTkxXTxkZiRrbm93bkVNW2RmJHllYXI9PTE5OTZdICYgZGYka25vd25FTVtkZiR5ZWFyPT0xOTk2XTxkZiRrbm93bkVNW2RmJHllYXI9PTIwMDddKXsKICAgICAgICBtYWYkdHJlbmRbbWFmJHBvc2l0aW9uPT1wb3NpdGlvbnNbaV1dPC0idXAiCiAgICB9CiAgICAKICAgIGVsc2UgbWFmJHRyZW5kW21hZiRwb3NpdGlvbj09cG9zaXRpb25zW2ldXTwtIm5vbmUiCn0KCndyaXRlLmNzdihtYWYsIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9jY3JjNl9NQUZjaGFuZ2VfY2hyMTVfMTZNYi5jc3YiKQoKZ2dwbG90KG1hZiwgYWVzKHg9eWVhciwgeT1rbm93bkVNLCBjb2xvcj1mYWN0b3IocG9zaXRpb24pKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MS41KSsKICAgIGdlb21fbGluZShzaXplPTAuMykrZ2d0aXRsZSgiQ0NSQzYgZ2VuZSBBRiBjaGFuZ2VzIikrCiAgICB5bGFiKCJtYWYiKSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpKwogICAgdGhlbWVfbWluaW1hbCgpK3RoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9NSksIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1BXU19jY3I2Y19BRmNoYW5nZV9jaDE1LnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0PTMsIGRwaT0zMDApCgojY29sb3IgYnkgdHJlbmQKbWFmJHRyZW5kPC1mYWN0b3IobWFmJHRyZW5kLCBsZXZlbHM9YygidXAiLCJkb3duIiwibm9uZSIpKQpnZ3Bsb3QobWFmLCBhZXMoeD15ZWFyLCB5PWtub3duRU0sIGNvbG9yPXRyZW5kKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MS41KSsKICAgIGdlb21fcGF0aChhZXMoZ3JvdXA9cG9zaXRpb24pLCBzaXplPTAuMykrZ2d0aXRsZSgiQ0NSQzYgZ2VuZSBBRiBjaGFuZ2VzIDE5OTEtMjAwNyIpKwogICAgeWxhYigibWFmIikrCiAgICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsKICAgIHRoZW1lX21pbmltYWwoKSt0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCgiVHJlbmQiLHZhbHVlcz1jKCJkZWVwcGluazIiLCJyb3lhbGJsdWUiLCAiZ3JheSIpKQpnZ3NhdmUoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9QV1NfY2NyNmNfQUZjaGFuZ2VfY2gxNV90cmVuZC5wbmciLCB3aWR0aCA9IDYsIGhlaWdodD0zLCBkcGk9MzAwKQoKdXA8LW1hZlttYWYkdHJlbmQ9PSJ1cCIsXQpkb3duPC1tYWZbbWFmJHRyZW5kPT0iZG93biIsXQpsaWJyYXJ5KGdncmVwZWwpCgojIFBsb3Qgc2VwYXJhdGVseQoKdXA8LXVwICU+JSBtdXRhdGUobGFiZWwgPSBpZl9lbHNlKHllYXIgPT0gbWF4KHllYXIpLCBhcy5jaGFyYWN0ZXIocG9zaXRpb24pLCBOQV9jaGFyYWN0ZXJfKSkKZ2dwbG90KHVwLCBhZXMoeD15ZWFyLCB5PWtub3duRU0pKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0xLjUsY29sb3I9ImRlZXBwaW5rMiIsIGFscGhhPTAuOCkrCiAgICBnZW9tX3BhdGgoYWVzKGdyb3VwPXBvc2l0aW9uKSwgc2l6ZT0wLjMsY29sb3I9ImRlZXBwaW5rMiIgKStnZ3RpdGxlKHBhc3RlMCgiQ0NSQzYgQUYgY2hhbmdlcyAxOTkxLTIwMDcsIFVwICIsbGVuZ3RoKCh1bmlxdWUobWFmJHBvc2l0aW9uW21hZiR0cmVuZD09InVwIl0pKSksIiBsb2NpIikpKwogICAgeWxhYigibWFmIikrCiAgICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsKICAgIHRoZW1lX21pbmltYWwoKSt0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fbGFiZWxfcmVwZWwoYWVzKGxhYmVsID0gbGFiZWwpLCBsYWJlbC5zaXplPTAuMSwgc2l6ZSA9IDIsCiAgICAgICAgICAgICAgICAgIG51ZGdlX3ggPSAyLAogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpCmdnc2F2ZSgiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1BXU19jY3I2Y19BRmNoYW5nZV9jaDE1X1VwLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0PTMsIGRwaT0zMDApCgpkb3duPC1kb3duICU+JSBtdXRhdGUobGFiZWwgPSBpZl9lbHNlKHllYXIgPT0gbWF4KHllYXIpLCBhcy5jaGFyYWN0ZXIocG9zaXRpb24pLCBOQV9jaGFyYWN0ZXJfKSkKZ2dwbG90KGRvd24sIGFlcyh4PXllYXIsIHk9a25vd25FTSkpKwogICAgZ2VvbV9wb2ludChzaXplPTEuNSxjb2xvcj0icm95YWxibHVlIiwgYWxwaGE9MC44KSsKICAgIGdlb21fcGF0aChhZXMoZ3JvdXA9cG9zaXRpb24pLCBzaXplPTAuMyxjb2xvcj0icm95YWxibHVlIiApK2dndGl0bGUocGFzdGUwKCJDQ1JDNiBBRiBjaGFuZ2VzIDE5OTEtMjAwNywgVXAgIixsZW5ndGgoKHVuaXF1ZShtYWYkcG9zaXRpb25bbWFmJHRyZW5kPT0iZG93biJdKSkpLCIgbG9jaSIpKSsKICAgIHlsYWIoIm1hZiIpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkrCiAgICB0aGVtZV9taW5pbWFsKCkrdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkrCiAgICAgZ2VvbV9sYWJlbF9yZXBlbChhZXMobGFiZWwgPSBsYWJlbCksIGxhYmVsLnNpemU9MC4xLCBzaXplID0gMywKICAgICAgICAgICAgICAgICAgbnVkZ2VfeCA9IDIsCiAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSkKZ2dzYXZlKCIuLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvUFdTX2NjcjZjX0FGY2hhbmdlX2NoMTVfZG93bi5wbmciLCB3aWR0aCA9IDYsIGhlaWdodD0zLCBkcGk9MzAwKQoKCgpgYGAKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvUFdTX2NjcjZjX0FGY2hhbmdlX2NoMTUucG5nKQohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL1BXU19jY3I2Y19BRmNoYW5nZV9jaDE1X3RyZW5kLnBuZykKCiFbXSguLi9PdXRwdXQvQ09WL0NPVnNjYW5fM3BvcC9jdXRvZmYvUFdTX2NjcjZjX0FGY2hhbmdlX2NoMTVfVXAucG5nKQoKIVtdKC4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9QV1NfY2NyNmNfQUZjaGFuZ2VfY2gxNV9kb3duLnBuZykKCiMjIyBBRiBjaGFuZ2VzIGluIGFsbCAzIHBvcHMKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCiMjI1RCCnBvcHM8LWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciLCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIsIlNTOTYiLCJTUzA2IiwiU1MxNyIpCnlyPC1jKDE5OTEsMTk5NiwyMDA2LDIwMTcsMTk5MSwxOTk2LDIwMDcsMjAxNywxOTk2LDIwMDYsMjAxNykKbWFmPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIGFmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL0FGLyIscG9wc1tpXSwiLm1hZnMiKSxzZXA9Ilx0IiwgaGVhZGVyID0gVCkKICAgIGFmPC1hZlthZiRjaHJvbW89PSJjaHIxNSImYWYkcG9zaXRpb24+PTE2MDUwMDAwJmFmJHBvc2l0aW9uPD0xNjEwMDAwMCxdCiAgICBhZiR5ZWFyPC15cltpXQogICAgYWYkcG9wPC1zdWIoIlxcZFxcZCIsIiIsIHBvcHNbaV0pCiAgICBtYWY8LXJiaW5kKG1hZixhZikKfQojd3JpdGUuY3N2KG1hZiwiLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvQUZfbWFmX2NocjEzXzIzTWIuY3N2IikKCgpnZ3Bsb3QobWFmLCBhZXMoeD15ZWFyLCB5PWtub3duRU0sIGNvbG9yPXBvcCkpKwogICAgZmFjZXRfd3JhcCh+ZmFjdG9yKHBvc2l0aW9uKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MS41KSsKICAgIGdlb21fcGF0aChsaW5ld2lkdGg9MC42KStnZ3RpdGxlKCJDQ1JDNiBnZW5lIChjaHIxNSkiKSsKICAgIHlsYWIoIm1hZiIpKwogICAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYygyLDMsMSldKQpnZ3NhdmUoIi4uL091dHB1dC9DT1YvQ09Wc2Nhbl8zcG9wL2N1dG9mZi9jY3JjNl9BRmNoYW5nZXNfYWxsUG9wcy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodD02LCBkcGk9MzAwKQoKYGBgCgohW10oLi4vT3V0cHV0L0NPVi9DT1ZzY2FuXzNwb3AvY3V0b2ZmL2NjcmM2X0FGY2hhbmdlc19hbGxQb3BzLnBuZykKCgoKCgoKCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCgoKCmBgYAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYGBgCgo=